2012-06-18 34 views
9

मैं उन परिवर्तनों पर पढ़ रहा हूं जो .NET4.5 लाएंगे, और this ब्लॉग पोस्ट पर मैंने कुछ ऐसी चीज पर ठोकर खाई जिसे मैं न जानता था और न ही समझ गया था।सी # भाषा जेनेरिकों को कब्रिस्तान होने से रोकती है जब तक कि उनमें कोई तरीका नहीं है जिसके लिए टी को इनपुट के रूप में आवश्यकता होती है?

जब केवल पढ़ने के लिए संग्रह के कार्यान्वयन के बारे में बात, Immo Landwerth का कहना है:

दुर्भाग्य से, हमारी प्रकार प्रणाली टी covariant के प्रकार बनाने जब तक यह नहीं तरीकों कि एक इनपुट के रूप टी लेते हैं अनुमति नहीं है। इसलिए, हम IReadOnlyList को इंडेक्सऑफ विधि नहीं जोड़ सकते हैं। हम मानते हैं कि यह अल्पसंख्यक के समर्थन के मुकाबले एक छोटा बलिदान है।

मेरी स्पष्ट रूप से समझ सीमित से ऐसा प्रतीत होता है जैसे वह कह रहा है इसी क्रम में एक विधि है कि एक IReadOnlyList<Circle> में पास करके एक IReadOnlyList<Shape> की आवश्यकता है कॉल करने के लिए हमें सक्षम करने के लिए, हम एक IReadOnlyList<T>.IndexOf(T someShape) विधि नहीं हो सकता।

मुझे नहीं पता कि प्रकार प्रणाली इसे कैसे रोकती है। क्या कोई समझा सकता है?

उत्तर

11

मान लीजिए CircleIEquatable<Circle> लागू करता है। यह उपलब्ध होने पर IReadOnlyList<Circle>.IndexOf द्वारा स्वाभाविक रूप से उपयोग किया जाएगा। अब आप लिख सकते हैं:

IReadOnlyList<Circle> circles = ...; 
IReadOnlyList<Shape> shapes = circles; 
int index = shapes.IndexOf(new Square(10)); 

कि एक Square जो स्पष्ट रूप से एक बुरा विचार किया जाएगा Circle.Equals(Circle) को पारित करने के लिए कोशिश कर रहा हो जाएंगे।

नियम जो इनपुट स्थिति में T के मानों को लागू नहीं करते हैं "सी # 4 spec के खंड 13.1.3 में हैं। लॉट अधिक जानकारी के लिए आपको Eric Lippert's blog series on generic variance भी पढ़ना चाहिए।

+0

पर्याप्त मेला। मैंने सोचा होगा कि इंडेक्सऑफ सिर्फ -1 लौटाएगा यदि उसे गलत प्रकार मिला है। डुनो मैंने ऐसा क्यों सोचा, कि प्रत्येक विधि में किसी प्रकार की जांच की आवश्यकता होगी। मैं एरिक के ब्लॉग पोस्ट में सही हो जाऊंगा। लड़का लेकिन वह आदमी कुछ समझ सकता है जिस तरह से मैं समझ सकता हूं! –

+0

क्या एक covariant 'IReadOnlyList ' लागू हो सकता है 'इंडेक्सऑफ (टीटी इसे)', जहां विधि का पैरामीटर प्रकार संग्रह से स्वतंत्र था। एक वर्ग 'सूची ' अपने 'इंडेक्सऑफ' को कार्यान्वित कर सकता है, फिर प्रत्येक प्रकार के 'टीटी' के लिए आलसी-जेनरेटेड (कैश) प्रतिनिधि का उपयोग कर सकता है, ताकि यदि 'टीआईटीएम 'लागू हो तो' IEquatable । इसके बाद यह एक प्रतिनिधि बन जाएगा स्थैतिक विधि जो इसे कॉल करेगी, और अन्यथा यह एक स्थिर विधि के लिए एक प्रतिनिधि बन जाएगी जो कुछ अन्य तुलनाओं का उपयोग करती है या कुछ प्रकार के संयोजन 'टीटी' और' टी' के लिए, केवल -1 लौटा दी जाती है। – supercat

1

ध्यान दें कि यह (यदि है कि अभी तक .NET में कार्यान्वित किया जाता है यकीन नहीं) सही, हो सकता है सिद्धांत रूप में, T के उपप्रकारों के लिए IndexOf परिभाषित करने के लिए:

class ReadOnlyList<+T> = { ... 
    Int IndexOf<U>(U elem) where T : U { ... } 
} 

यह दिलचस्प कारण है कि IndexOf(T elem) होगा देखने के लिए जाहिर तौर पर कॉन्वेंट नहीं है, जबकि यह एक है: यदि आपके पास T2 : T1 है, तो एक विधि IndexOf(T1 elem) हस्ताक्षर IndexOf(T2 elem) हस्ताक्षर के साथ संगत नहीं हो सकता है। इसके विपरीत, यदि आपके पास IndexOf<U>(U elem) where T1 : U है, तो आप जानते हैं कि T2 : T1 और T1 : U, इसलिए आपके पास T2 : U भी ऐसे सभी U के लिए है: यह प्रकार IndexOf<U>(U elem) with T2 : U का उप-प्रकार है।

यह टिप्पणी, उदाहरण के लिए, 2006 के लेख Variance and Generalized Constraints for C# Generics में एमीर, केनेडी, रूसो और यू द्वारा: वे एक प्रकार की प्रणाली पेश करते हैं जो इस परिभाषा को स्वीकार करेगी।

+0

मुझे नहीं लगता कि सामान्य 'इंडेक्सऑफ' के पैरामीटर को बाधित किया जाना चाहिए। 'सूची ' पूछना पूरी तरह से उचित है कि इसमें 'Animal', या' SiameseCat', या यहां तक ​​कि 'कुत्ते' का एक दिया गया उदाहरण शामिल है। – supercat

+0

उन सभी उदाहरणों को मेरे द्वारा दिए गए हस्ताक्षर के साथ अनुमति दी जाएगी, या तो तर्क पर या सूची में स्वयं का उपयोग करके। 'सियामीज़ैट '' बिल्ली' का एक सुपरटेप है ताकि आप सीधे 'सूची .indexOf ' का उपयोग कर सकें। एक 'सूची ' एक 'सूची ' भी है, इसलिए आप 'सूची .indexOf ' या 'सूची .indexOf ' का उपयोग कर सकते हैं। तुलना दो वस्तुओं के सबसे सटीक आम सुपरक्लास पर की जाएगी। – gasche

+0

मेरा मुद्दा यह है कि 'पठनीय सूची के साथ कुछ भी गलत नहीं है IndexOf '। यदि असंबद्ध जेनेरिक प्रकार पैरामीटर 'टी' और' यू 'वाले वर्ग में विधि' foo' 'को' पठनीय सूची सूची' और 'यू आइटम' प्राप्त होता है, और जानना चाहता है कि 'सूची' में' आइटम' है, तो वह क्वेरी होगी अर्थपूर्ण हो अगर 'टी' उप-वर्ग या' यू' का सुपरक्लास है, और जब प्रकार असंबंधित होते हैं तब भी अच्छी तरह से परिभाषित अर्थशास्त्र होगा। प्रश्न 'टी' और 'यू 'के बीच किसी भी वर्ग संबंध को निर्धारित करने के लिए' foo' की आवश्यकता नहीं होनी चाहिए, खासकर जब सूची और आइटम के वास्तविक प्रकार इंडेक्सऑफ विधि ... – supercat

6

चूंकि IReadOnlyList<T> कॉन्वर्सेंट है, तो आप इसे T के किसी भी सुपरटेप में डाल सकते हैं और सभी विधियों को अभी भी अनुबंध के अनुसार काम करना चाहिए। T का सबसे सुपर सुपरटेप Object है, इसलिए IndexOf इंटरफ़ेस का हिस्सा थे, तो इसे Object स्वीकार कर लेना चाहिए था।

जैसा कि जॉन स्कीट Circle ऑब्जेक्ट्स की सूची में बताता है, तो आप पूछ सकते हैं: इस सूची में किसी विशेष Square की अनुक्रमणिका क्या है? एकमात्र सही प्रतिक्रिया "यह यहां नहीं है," और IndexOf को वापस लौटना चाहिए और अपवाद नहीं फेंकना चाहिए।

तो, मैं जॉन स्कीट से सहमत नहीं हूं।

int IndexOf(object item); 

वास्तव में एक ही तर्क IReadOnlyCollection में Contains पर लागू होता है: जब आप एक वस्तु में पारित covariant सामान्य मापदंडों की सीमाओं को देखते हुए, और ArrayList.indexOf in Java के समान है, बीसीएल टीम निम्नलिखित हस्ताक्षर के साथ एक विधि IndexOf शामिल किया जाना चाहिए था एक असंगत प्रकार के, संग्रह में स्पष्ट रूप से यह शामिल नहीं है और विधि को false वापस करना चाहिए।

एकमात्र नकारात्मक मूल्य मूल्य प्रकारों का मुक्केबाजी होगा, लेकिन वास्तविक कार्यान्वयन अभी भी IReadOnlyList.IndexOf विधि को छुपा सकता है और यह तर्क उत्पन्न करने के लिए अपना स्वयं का सामान्य अधिभार प्रदान कर सकता है।

तो, आप IndexOf की अपेक्षा करने में सही हैं, जब एक असंगत वस्तु पारित की जाती है, तो यह इंटरफ़ेस पर होती है।


मैं दिखाने के लिए कि यह कैसे व्यवहार में काम करेगा मेरी M42.Collections पुस्तकालय में इस सिद्धांत को लागू किया। आप इसे यहां डाउनलोड कर सकते हैं:

M42 Collections - पोर्टेबल .NET लाइब्रेरी संग्रह के साथ काम करने के लिए ठीक से काम करने के लिए।

+0

'बराबर' के पैरामीटर मजाकिया है, उसमें एक प्रदर्शन दृष्टिकोण से यह बेन हो सकता है सामान्य होने से efit, लेकिन एक अर्थपूर्ण दृष्टिकोण से यह दोनों covariant और contravariant (अर्थ वास्तव में जेनेरिक नहीं है) है। 'सूची ' को "ऐसी चीज़" के रूप में माना जा सकता है, जिसमें पूछा जा सकता है कि इसमें दिया गया है 'सियामीज़ कैट', या "चीज़ ... दिया गया 'पशु', या यहां तक ​​कि" चीज ... दिया गया 'कुत्ता' "। बाद के मामले में जवाब "नहीं" होगा, लेकिन इसका मतलब यह नहीं है कि सवाल नहीं पूछा जा सका। – supercat