क्या स्पष्ट कास्टिंग ऑपरेटर का मेरा उपयोग उचित या खराब हैक है?


24

मेरे पास एक बड़ी वस्तु है:

class BigObject{
    public int Id {get;set;}
    public string FieldA {get;set;}
    // ...
    public string FieldZ {get;set;}
}

और एक विशेष, डीटीओ जैसी वस्तु:

class SmallObject{
    public int Id {get;set;}
    public EnumType Type {get;set;}
    public string FieldC {get;set;}
    public string FieldN {get;set;}
}

मुझे व्यक्तिगत रूप से BigObject की स्मालऑबजेक्ट में स्पष्ट रूप से कास्टिंग की अवधारणा मिली - यह जानते हुए कि यह एक तरफ़ा, डेटा-खोने वाला ऑपरेशन है - बहुत सहज और पठनीय:

var small = (SmallObject) bigOne;
passSmallObjectToSomeone(small);

यह स्पष्ट ऑपरेटर का उपयोग करके कार्यान्वित किया जाता है:

public static explicit operator SmallObject(BigObject big){
    return new SmallObject{
        Id = big.Id,
        FieldC = big.FieldC,
        FieldN = big.FieldN,
        EnumType = MyEnum.BigObjectSpecific
    };
}

अब, मैं विधि के SmallObjectFactoryसाथ एक वर्ग बना सकता हूं FromBigObject(BigObject big), जो एक ही काम करेगा, इसे निर्भरता इंजेक्शन में जोड़ें और जब आवश्यकता हो तब इसे कॉल करें ... लेकिन मुझे यह और भी अधिक जटिल और अनावश्यक लगता है।

PS मुझे यकीन नहीं है कि यह प्रासंगिक है, लेकिन ऐसा होगा OtherBigObjectजो SmallObjectअलग-अलग सेटिंग में परिवर्तित करने में सक्षम होगा EnumType


4
कंस्ट्रक्टर क्यों नहीं?
edc65

2
या एक स्थिर कारखाने विधि?
ब्रायन गॉर्डन

आपको फैक्ट्री क्लास, या निर्भरता इंजेक्शन की आवश्यकता क्यों होगी? आपने वहां एक गलत द्वंद्व बनाया है।
user253751

1
@ मिनीबिस - क्योंकि मैंने किसी तरह @Telastyn प्रस्तावित: .ToSmallObject()विधि (या GetSmallObject()) के बारे में नहीं सोचा था । कारण की एक क्षणिक कमी - मुझे पता था कि कुछ मेरी सोच के साथ गलत है, इसलिए मैंने आप लोगों से पूछा है :)
गेरिनो

3
यह एक ISmallObject इंटरफ़ेस के लिए एक सही उपयोग के मामले की तरह लगता है जो केवल BigObject द्वारा अपने व्यापक डेटा / व्यवहार के सीमित सेट तक पहुंच प्रदान करने के लिए एक साधन के रूप में लागू किया जाता है। विशेष रूप से जब @ टेलस्टीन के एक ToSmallObjectविधि के विचार के साथ संयुक्त ।
मार्जन वेनमा

जवाबों:


0

मेरे विनम्र मत में किसी भी अन्य उत्तर का अधिकार नहीं है। इस स्टैकओवरफ़्लो में उच्चतम-वोट वाले उत्तर का तर्क है कि मैपिंग कोड को डोमेन से बाहर रखा जाना चाहिए। आपके प्रश्न का उत्तर देने के लिए, नहीं - कास्ट ऑपरेटर का आपका उपयोग महान नहीं है। मैं एक मैपिंग सेवा बनाने की सलाह दूंगा जो आपके डीटीओ और आपके डोमेन ऑब्जेक्ट के बीच बैठता है, या आप इसके लिए ऑटोमैपर का उपयोग कर सकते हैं।


यह एक भयानक विचार है। मेरे पास पहले से ही ऑटोमैपर है, इसलिए यह एक हवा होगी। केवल मेरे पास यह मुद्दा है: क्या बिगऑबजेक्ट और स्मॉलऑबजेक्ट किसी तरह से संबंधित नहीं हैं?
गेरिनो

1
नहीं, मैं BigObject और SmallObject को एक साथ मैपिंग सेवा के अलावा आगे जोड़कर कोई फायदा नहीं देखता।
एसेन स्कोव पेडरसन

7
वास्तव में? एक automapper डिजाइन समस्याओं के लिए अपने समाधान है?
तेलस्टिन

1
BigObject, SmallObject के लिए अनुपयुक्त है, वे वास्तव में शास्त्रीय OOP अर्थों में एक-दूसरे से संबंधित नहीं हैं, और कोड यह दर्शाता है (दोनों ऑब्जेक्ट डोमेन में मौजूद हैं, मैपिंग की क्षमता मैपिंग कॉन्फ़िगरेशन में कई अन्य लोगों के साथ सेट है)। यह संदिग्ध कोड (मेरे दुर्भाग्यपूर्ण ऑपरेटर ओवरराइड) को हटा देता है, यह मॉडल को साफ करता है (उनमें कोई भी विधि नहीं है), इसलिए, हाँ, यह एक समाधान प्रतीत होता है।
गेरिनो

2
@EsbenSkovPedersen यह समाधान आपके मेलबॉक्स को स्थापित करने के लिए एक छेद खोदने के लिए बुलडोजर का उपयोग करने जैसा है। सौभाग्य से ओपी वैसे भी यार्ड खोदना चाहता था, इसलिए इस मामले में एक बुलडोजर काम करता है। हालाँकि, मैं सामान्य रूप से इस समाधान की सिफारिश नहीं करूंगा ।
नील

81

यह है ... महान नहीं है। मैंने कोड के साथ काम किया है जिसने इस चालाक चाल को किया और इससे भ्रम पैदा हुआ। आखिरकार, आप उम्मीद करेंगे कि यदि ऑब्जेक्ट्स उन्हें कास्ट करने के लिए पर्याप्त संबंधित हैं, तो वे केवल BigObjectएक SmallObjectचर में असाइन करने में सक्षम होंगे । हालांकि यह काम नहीं करता है - आपको कंपाइलर त्रुटियां मिलती हैं यदि आप कोशिश करते हैं कि जहां तक ​​टाइप सिस्टम का संबंध है, वे असंबंधित हैं। कास्टिंग ऑपरेटर के लिए नई वस्तुओं को बनाने के लिए यह हल्के से भी अप्रिय है।

मैं .ToSmallObject()इसके बजाय एक विधि की सिफारिश करूंगा । यह स्पष्ट है कि वास्तव में क्या हो रहा है और क्रिया के बारे में क्या है।


18
दोह ... ToSmallObject () सबसे स्पष्ट पसंद की तरह लगता है। कभी-कभी सबसे स्पष्ट सबसे मायावी होता है;)
गेरिनो

6
mildly distastefulएक समझ है। यह दुर्भाग्यपूर्ण है कि भाषा टाइपकास्ट की तरह दिखने के लिए इस तरह की अनुमति देती है। कोई भी यह अनुमान नहीं लगाएगा कि यह एक वास्तविक वस्तु परिवर्तन था जब तक कि उन्होंने इसे स्वयं नहीं लिखा। एक-व्यक्ति टीम में, ठीक। यदि आप किसी के साथ सहयोग करते हैं, तो सबसे अच्छे मामले में यह समय की बर्बादी है क्योंकि आपको रोकना है और यह पता लगाना है कि क्या यह वास्तव में एक कलाकार है, या यदि यह उन पागल परिवर्तनों में से एक है।
केंट ए

3
@Telastyn सहमत है कि यह सबसे गंभीर कोड गंध नहीं है। लेकिन ऑपरेशन से एक नई वस्तु की छिपी हुई रचना जो कि अधिकांश प्रोग्रामर कंपाइलर को निर्देश देते हैं कि वह उसी ऑब्जेक्ट को एक अलग प्रकार का इलाज करने के लिए समझे , जो आपके बाद आपके कोड के साथ काम करना है। :)
केंट ए

4
के लिए +1 .ToSmallObject()। शायद ही कभी आपको ऑपरेटरों को ओवरराइड करना चाहिए।
ytoledano

6
@dorus - कम से कम .NET में, Getतात्पर्य किसी मौजूदा चीज़ को वापस करने से है। जब तक आपने छोटी वस्तु पर परिचालन को ओवरराइड नहीं किया है, दो Getकॉल असमान वस्तुएं लौटाएंगे, जिससे भ्रम / कीड़े / wtfs हो सकते हैं।
तेलस्टिन

11

जबकि मैं देख सकता हूं कि आपको ए की आवश्यकता क्यों होगी SmallObject, मैं समस्या को अलग तरीके से देखूंगा । इस प्रकार के मुद्दे के लिए मेरा दृष्टिकोण एक मुखौटा का उपयोग करना है । इसका एकमात्र उद्देश्य इनकैप्सुलेट करना BigObjectऔर केवल विशिष्ट सदस्यों को उपलब्ध कराना है। इस तरह, यह एक ही उदाहरण पर एक नया इंटरफ़ेस है, न कि एक प्रति। बेशक आप एक प्रति भी प्रदर्शन करना चाहते हैं, लेकिन मैं आपको सलाह दूंगा कि आप इस उद्देश्य के लिए बनाए गए एक विधि के माध्यम से ऐसा करें, जो कि (उदाहरण के लिए return new SmallObject(instance.Clone())) के साथ संयोजन में हो ।

मुखौटा के पास कई अन्य फायदे हैं, अर्थात् यह सुनिश्चित करना कि आपके कार्यक्रम के कुछ अनुभाग केवल आपके मुखौटा के माध्यम से उपलब्ध कराए गए सदस्यों का उपयोग कर सकते हैं, प्रभावी रूप से यह गारंटी देते हैं कि यह उस चीज का उपयोग नहीं कर सकता है जिसके बारे में उसे पता नहीं होना चाहिए। इसके अतिरिक्त, इसका एक बड़ा फायदा यह भी है कि BigObjectभविष्य के रखरखाव में बदलने के लिए आपके पास अधिक लचीलापन है, बिना यह चिंता किए बिना कि यह आपके पूरे कार्यक्रम में कैसे उपयोग किया जाता है। जब तक आप पुराने व्यवहार को किसी रूप या किसी अन्य रूप में अनुकरण कर सकते हैं, तब तक आप SmallObjectउसी तरह से काम कर सकते हैं जैसा कि पहले किए बिना अपने कार्यक्रम को बदलने के लिए हर जगह BigObjectकिया जाता था।

ध्यान दें, इसका मतलब इस BigObjectपर निर्भर नहीं करता है SmallObject, बल्कि अन्य तरीके से भी होता है (जैसा कि मेरे विनम्र विचार में होना चाहिए)।


केवल एक ही लाभ जो आपने उल्लेख किया है कि एक नया वर्ग के लिए खेतों की नकल करने के लिए एक मुखौटा है (जो शायद तब तक कोई समस्या नहीं है जब तक कि वस्तुओं के खेतों की एक बेतुकी राशि न हो)। दूसरी ओर इसका नुकसान यह है कि आपको हर बार मूल वर्ग को संशोधित करना होगा, जब आपको एक स्थिर रूपांतरण विधि के विपरीत एक नई कक्षा में परिवर्तित करना होगा।
डोभाल

@ डोवाल मुझे लगता है कि यह बात है। आप इसे एक नए वर्ग में नहीं बदलेंगे। यदि आप की आवश्यकता है तो आप एक और पहलू बना सकते हैं। BigObject में किए गए बदलावों को केवल मुखौटा वर्ग पर लागू करने की आवश्यकता है और हर जगह नहीं जहां इसका उपयोग किया जाता है।
नील

इस दृष्टिकोण और के बीच एक दिलचस्प भेद Telastyn के जवाब पैदा करने के लिए है कि क्या जिम्मेदारी है SmallObjectके साथ झूठ SmallObjectया BigObject। डिफ़ॉल्ट रूप से, यह दृष्टिकोण SmallObjectनिजी / संरक्षित सदस्यों पर निर्भरता से बचने के लिए मजबूर करता है BigObject। हम एक कदम आगे जा सकते हैं और विस्तार विधि SmallObjectका उपयोग करके निजी / संरक्षित सदस्यों पर निर्भरता से बच सकते हैं ToSmallObject
ब्रायन

@ ब्रायन आप BigObjectइस तरह से अव्यवस्था का जोखिम उठाते हैं । यदि आप कुछ ऐसा ही करना चाहते हैं, तो आप एक ToAnotherObjectविस्तार विधि बनाने के लिए जोर देंगे BigObject? ये चिंता का विषय नहीं होना चाहिए BigObject, संभवतः, यह पहले से ही काफी बड़ा है जैसा कि यह है। यह आपको BigObjectइसकी निर्भरता के निर्माण से अलग करने की भी अनुमति देता है , जिसका अर्थ है कि आप कारखानों और इस तरह का उपयोग कर सकते हैं। अन्य दृष्टिकोण दृढ़ता से जोड़े BigObjectऔर SmallObject। यह इस विशेष मामले में ठीक हो सकता है, लेकिन यह मेरी विनम्र राय में सबसे अच्छा अभ्यास नहीं है।
नील

1
@Neil वास्तव में, ब्रायन यह गलत बताया गया है, लेकिन वह है सही - विस्तार तरीकों युग्मन से छुटकारा पाने के है। इसे अब BigObjectयुग्मित नहीं किया जा रहा है SmallObject, यह कहीं न कहीं एक स्थिर तरीका है जो एक तर्क BigObjectदेता है और रिटर्न देता है SmallObject। विस्तार विधियाँ वास्तव में सिस्टेमैटिक शुगर हैं जो स्थैतिक तरीकों को अच्छे तरीके से कहते हैं। विस्तार विधि का हिस्सा नहीं है BigObject, यह एक पूरी तरह से अलग स्थैतिक विधि है। यह वास्तव में विस्तार विधियों का एक बहुत अच्छा उपयोग है, और विशेष रूप से डीटीओ रूपांतरणों के लिए बहुत आसान है।
लुआं

6

एक बहुत ही मजबूत सम्मेलन है जो परिवर्तनशील संदर्भ प्रकारों पर कास्ट पहचान-संरक्षण है। क्योंकि सिस्टम आम तौर पर उन स्थितियों में उपयोगकर्ता-परिभाषित कास्टिंग ऑपरेटरों की अनुमति नहीं देता है, जहां स्रोत प्रकार का एक ऑब्जेक्ट गंतव्य प्रकार के संदर्भ में सौंपा जा सकता है, केवल कुछ ही मामले हैं जहां उपयोगकर्ता-परिभाषित कास्टिंग ऑपरेशन पारस्परिक संदर्भ के लिए उचित होंगे प्रकार के।

मैं एक आवश्यकता के रूप में सुझाव दूंगा, जिसे x=(SomeType)foo;कुछ समय बाद दिया गया है y=(SomeType)foo;, दोनों जातियों को एक ही वस्तु पर लागू करने के साथ, x.Equals(y)हमेशा और हमेशा के लिए सही होना चाहिए, भले ही प्रश्न में वस्तु को दो जातियों के बीच संशोधित किया गया हो। ऐसी स्थिति लागू हो सकती है जैसे कि किसी के पास विभिन्न प्रकार की वस्तुओं की एक जोड़ी होती है, जिनमें से प्रत्येक में दूसरे के लिए एक अपरिवर्तनीय संदर्भ होता है, और अन्य प्रकार के ऑब्जेक्ट को कास्टिंग करने से इसका जोड़ा उदाहरण वापस आ जाएगा। यह उन प्रकारों के साथ भी लागू हो सकता है जो परस्पर परिवर्तनशील वस्तुओं के रैपर के रूप में काम करते हैं, बशर्ते कि लपेटी जा रही वस्तुओं की पहचान अपरिवर्तनीय थी, और एक ही प्रकार के दो रैपर स्वयं को समान रूप से रिपोर्ट करेंगे यदि वे समान संग्रह को लपेटते हैं।

आपका विशेष उदाहरण उत्परिवर्तनीय वर्गों का उपयोग करता है, लेकिन पहचान के किसी भी रूप को संरक्षित नहीं करता है; जैसा कि, मैं सुझाव दूंगा कि यह कास्टिंग ऑपरेटर का उचित उपयोग नहीं है।


1

यह ठीक हो सकता है।

आपके उदाहरण के साथ एक समस्या यह है कि आप ऐसे उदाहरण-ईश नामों का उपयोग करते हैं। विचार करें:

SomeMethod(long longNum)
{
  int num = (int)longNum;
  /* ... */

अब, जब आप एक अच्छा विचार है कि क्या एक लंबा और है पूर्णांक मतलब है, तो के अंतर्निहित कलाकारों दोनों intके लिए longऔर से स्पष्ट कलाकारों longको intकाफी समझा जा सकता है। यह भी समझ में आता है कि कैसे 3बनता है 3और काम करने का सिर्फ एक और तरीका है 3। यह समझा जा सकता है कि int.MaxValue + 1चेक किए गए संदर्भ में यह कैसे विफल होगा । यहां तक ​​कि यह int.MaxValue + 1अनियंत्रित संदर्भ के साथ कैसे काम करेगा परिणाम के int.MinValueलिए सबसे मुश्किल काम नहीं है।

इसी तरह, जब आप एक आधार प्रकार के लिए या स्पष्ट रूप से एक व्युत्पन्न प्रकार को स्पष्ट रूप से डालते हैं, तो किसी को भी यह समझ में आता है कि विरासत कैसे काम करती है, और परिणाम क्या होगा (या यह कैसे विफल हो सकता है)।

अब, BigObject और SmallObject के साथ, मुझे यह समझ नहीं है कि यह रिश्ता कैसे काम करता है। यदि आपके वास्तविक प्रकार जहां इस तरह के हैं, जहां संबंध स्पष्ट हैं, तो कास्टिंग वास्तव में एक अच्छा विचार हो सकता है, हालांकि बहुत समय, शायद विशाल बहुमत, यदि यह मामला है तो यह वर्ग पदानुक्रम और में परिलक्षित होना चाहिए सामान्य वंशानुक्रम आधारित कास्टिंग पर्याप्त होगी।


वास्तव में वे प्रश्न में प्रदान किए गए से अधिक नहीं हैं - लेकिन उदाहरण के लिए BigObjectएक का वर्णन कर सकते हैं Employee {Name, Vacation Days, Bank details, Access to different building floors etc.}, और SmallObjectएक हो सकता है MoneyTransferRecepient {Name, Bank details}। से सीधा अनुवाद Employeeहै MoneyTransferRecepient, और बैंकिंग एप्लिकेशन को आवश्यकता से अधिक डेटा भेजने का कोई कारण नहीं है।
गेरिनो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.