जेनरिक दुरुपयोग क्या है?


35

कुछ कोड की समीक्षा करते समय, मैंने जेनरिक का उपयोग करने के लिए इसे बदलने का अवसर देखा। (अस्पष्ट) कोड जैसा दिखता है:

public void DoAllTheThings(Type typeOfTarget, object[] possibleTargets)
{
    var someProperty = typeOfTarget.GetProperty(possibleTargets[0]);
    ...
}

इस कोड को जेनेरिक द्वारा प्रतिस्थापित किया जा सकता है, जैसे:

public void DoAllTheThings<T>(object[] possibleTargets[0])
{
    var someProperty = type(T).getProperty(possibleTargets[0]);
    ...
}

इस दृष्टिकोण के लाभों और कमियों पर शोध करने में मुझे एक शब्द मिला जिसका नाम सामान्य दुर्व्यवहार है । देख:

मेरा प्रश्न दो भागों में आता है:

  1. क्या इस तरह से जेनरिक में जाने के कोई लाभ हैं? (प्रदर्शन? पठनीयता?)
  2. जेनरिक एब्यूज क्या है? और हर बार एक जेनेरिक का उपयोग करते हुए एक प्रकार का पैरामीटर एक दुरुपयोग है ?

2
मैं उलझन में हूं। आप पहले से ही संपत्ति का नाम जानते हैं लेकिन उस वस्तु का प्रकार नहीं है जिससे आप मूल्य प्राप्त करने के लिए प्रतिबिंब का उपयोग करते हैं?
मेटाफ़ाइट

3
@ मीटाफाइट मैं इसे जटिल उदाहरण जानता हूं, वास्तविक कोड यहां डालने के लिए लंबा और कठिन होगा। बावजूद, मेरे प्रश्न का उद्देश्य यह निर्धारित करना है कि क्या सामान्य के साथ टाइप पैरामीटर को प्रतिस्थापित करना अच्छा या खराब रूप माना जाता है।
SyntaxRules

12
मैंने हमेशा माना है कि सामान्य कारण क्यों जेनरिक मौजूद है (स्वादिष्ट सजा का इरादा नहीं है)। जब आप अपने प्रकार की प्रणाली का लाभ उठा सकते हैं, तो आप अपने आप को टाइप ट्रिकरी क्यों करते हैं?
मेटाफ़ाइट

2
आपका उदाहरण अजीब है, लेकिन मुझे यह महसूस हो रहा है कि वास्तव में बहुत सारे आईओडी पुस्तकालय क्या करते हैं
इवान

14
उत्तर नहीं, लेकिन यह ध्यान देने योग्य है कि दूसरा उदाहरण पहले की तुलना में कम लचीला है। फ़ंक्शन को सामान्य बनाने से आपकी रनटाइम प्रकार में पास करने की क्षमता समाप्त हो जाती है; संकलन के समय जेनरिक के प्रकार को जानना आवश्यक है।
KChaloux

जवाबों:


87

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

आपके उदाहरण के संबंध में, मैं object[]एक T[]या समान को बदलने और पूरी तरह से बचने Typeया इससे बचने के लिए जेनरिक के उचित उपयोग की उम्मीद करूंगा type। इसके लिए अन्य जगहों पर महत्वपूर्ण रीफैक्टरिंग की आवश्यकता हो सकती है, लेकिन यदि इस मामले में जेनेरिक का उपयोग उचित है, तो जब आप कर रहे हों, तो यह समग्र रूप से सरल होना चाहिए।


3
यह एक महान बिंदु है। मैं उस कोड को स्वीकार करूंगा जो मुझे यह सोचकर मिला था कि प्रतिबिंब पढ़ने के लिए कुछ कठिन प्रदर्शन कर रहा था। मैं अगर मैं बदल सकते हैं देखेंगे object[]करने के लिए T[]
सिंटेक्सRules

3
मुझे हटाने बनाम पुनर्व्यवस्थित चरित्रांकन पसंद है।
ताम्र

13
आपने जेनरिक के एक महत्वपूर्ण उपयोग को याद किया - जो दोहराव को कम करने के लिए है। (हालांकि आप उन अन्य पापों का उल्लेख करके दोहराव को कम कर सकते हैं जो आप उल्लेख करते हैं)। यदि यह किसी भी टाइपकास्ट, प्रतिबिंब, या गतिशील टाइपिंग IMO को हटाए बिना दोहराव को कम करता है तो यह ठीक है।
माइकल एंडरसन

4
बहुत बढ़िया जवाब। मुझे लगता है कि इस विशेष मामले में, ओपी को जेनेरिक के बजाय एक इंटरफ़ेस पर स्विच करने की आवश्यकता हो सकती है । ऐसा लगता है जैसे कि प्रतिबिंब का उपयोग वस्तु के विशेष गुणों तक पहुंचने के लिए किया जा रहा है; कंपाइलर को यह निर्धारित करने की अनुमति देने के लिए एक इंटरफ़ेस बहुत बेहतर अनुकूल है कि इस तरह के गुण वास्तव में मौजूद हैं।
jpmc26

4
@MichaelAnderson "कोड को हटाने के बजाय इसे फिर से व्यवस्थित करें" इसमें दोहराव को कम करना शामिल है
Caleth

5

मैं नो-नॉनसेंस नियम का उपयोग करूंगा: जेनरिक, अन्य सभी प्रोग्रामिंग कंस्ट्रक्शन की तरह, एक समस्या को हल करने के लिए मौजूद है । अगर जेनरिक के समाधान के लिए कोई समस्या नहीं है, तो उनका उपयोग करना दुरुपयोग है।

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

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


ऐसा लगता है कि यह बहुत अधिक कठिन है, इसलिए मुझे आपको याद दिलाना चाहिए:
प्रोग्रामिंग में अपवाद के बिना कोई नियम नहीं है। इस नियम में शामिल थे।


दिलचस्प विचार। हालाँकि आपके मानदंड में थोड़ी सी फेरबदल से मदद मिल सकती है। मान लीजिए कि ओपी को एक नए "घटक" की आवश्यकता है, जो एक स्ट्रिंग के लिए एक इंट को मैप करता है और इसके विपरीत। यह बहुत स्पष्ट है कि यह एक सामान्य आवश्यकता को हल करता है और भविष्य में आसानी से पुन: प्रयोज्य हो सकता है यदि इसे सामान्य बनाया जाए। यह मामला आपकी जेनेरिक दुर्व्यवहार की परिभाषा में आएगा। हालांकि, एक बार बहुत ही सामान्य अंतर्निहित आवश्यकता की पहचान हो जाने के बाद, क्या यह एक अपमानजनक अतिरिक्त प्रयास है कि यह एक दुरुपयोग के बिना डिजाइन में अतिरिक्त निवेश करने के लिए लायक नहीं होगा?
क्रिस्टोफ

@Christophe यह वास्तव में एक मुश्किल सवाल है। हां, कुछ परिस्थितियां हैं जहां मेरे नियम को अनदेखा करना बेहतर है (प्रोग्रामिंग में अपवाद के बिना कोई नियम नहीं है!)। हालांकि, विशिष्ट स्ट्रिंग रूपांतरण का मामला वास्तव में शामिल है: 1. आपको अलग से हस्ताक्षरित और अहस्ताक्षरित प्रकार के उपचार की आवश्यकता है। 2. आपको पूर्णांक रूपांतरण से अलग फ्लोट रूपांतरण का इलाज करने की आवश्यकता है। 3. आप छोटे प्रकार के लिए सबसे बड़े उपलब्ध पूर्णांक प्रकारों के लिए कार्यान्वयन का पुन: उपयोग कर सकते हैं। आप सक्रिय रूप से कास्टिंग करने के लिए एक जेनेरिक रैपर लिखना चाहते हैं, लेकिन कोर जेनेरिक के बिना होगा।
cmaster

1
मैं YAGNI के रूप में सक्रिय रूप से फिर से उपयोग करने के बजाय एक जेनेरिक (पूर्व-उपयोग) लिखने के खिलाफ तर्क दूंगा। जब आपको इसकी आवश्यकता हो, तो रिफ्लेक्टर।
नील_यूके

इस सवाल को लिखने पर मैंने "भविष्य में संभावित पुन: उपयोग को बचाने के लिए यदि संभव हो तो इसे सामान्य के रूप में लिखें" का रुख अधिक लिया। मुझे पता था कि थोड़ा अतिवादी था। यहां आपकी बात को देखने के लिए यह ताज़ा है। धन्यवाद!
SyntaxRules

0

कोड अजीब लगता है। लेकिन अगर हम इसे बुला रहे हैं, तो यह एक सामान्य के रूप में निर्दिष्ट करने के लिए अच्छा लग रहा है।

https://stackoverflow.com/questions/10955579/passing-just-a-type-as-a-parameter-in-c-sharp

व्यक्तिगत रूप से मुझे ये अंतर्विरोध पसंद नहीं हैं जो कॉलिंग कोड को सुंदर बनाते हैं। उदाहरण के लिए पूरी 'धाराप्रवाह' चीज और विस्तार के तरीके।

लेकिन आपको यह स्वीकार करना होगा कि इसका एक लोकप्रिय अनुसरण है। यहाँ तक कि Microsoft इसका उपयोग एकता में उदाहरण के लिए करते हैं

container.RegisterType<IInterface,Concrete>()

0

मेरे लिए ऐसा लगता है कि आप यहाँ सही रास्ते पर थे, लेकिन काम पूरा नहीं किया।

क्या आपने अगले चरण के लिए object[]पैरामीटर बदलने पर विचार किया है Func<T,object>[]?

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.