2011-08-14 13 views
8

मैं हाल ही में सी # मूल बातें के बारे में मेरी स्मृति को ताज़ा करने का निर्णय लिया है, तो यह तुच्छ हो सकता है, लेकिन मैं निम्न समस्या से टकरा गया है:सी # सहप्रसरण और contravariance लागू करते समय इंटरफेस

StringCollection नेट v1 में उपयोग किया गया आदेश स्ट्रिंग के रूप में एक object आधारित ArrayList करने का विरोध के लिए एक जोरदार टाइप किया संग्रह बनाने के लिए में .0 (यह बाद में जेनेरिक संग्रह सहित द्वारा बढ़ाया गया था):

StringCollection परिभाषा पर एक नज़र ले रहा है, तो आपको निम्न देख सकते हैं:

// Summary: 
//  Represents a collection of strings. 
[Serializable] 
public class StringCollection : IList, ICollection, IEnumerable 
{ 
... 
    public int Add(string value); 
... 
} 

आप देख सकते हैं यह लागू करता IList है, जो निम्नलिखित घोषणा (कुछ अन्य घोषणाओं के बीच) शामिल हैं:

int Add(object value); 

लेकिन नहीं:

int Add(string value); 

मेरी पहली धारणा है कि यह कारण संभव है था .NET ढांचे covariance नियम।

तो बस सुनिश्चित करने के लिए, मैं अपने ही वर्ग जो IList लागू करता है लेखन की कोशिश की और

int Add(object value); 

बदल एक स्ट्रिंग एक वस्तु लिखने के बजाय टाइप पुनः प्राप्त करने के लिए, लेकिन मेरे आश्चर्य के लिए, जब परियोजना को संकलित करने की कोशिश कर रहा , मुझे एक संकलन-समय त्रुटि मिली:

does not implement interface member 'System.Collections.IList.Add(object)' 

कोई विचार क्या कारण है?

धन्यवाद!

उत्तर

7

व्यवहार सह/contravariance के बजाय IList.Add(object) के स्पष्ट कार्यान्वयन के कारण होता है। एमएसडीएन दस्तावेज के अनुसार, स्ट्रिंगकोलेक्शन स्पष्ट रूप से IList.Add(object) लागू करता है; Add(string) विधि असंबंधित है।

class StringCollection : IList 
{ 
    ... 
    public int Add(string value) 
    {} // implementation 

    public int IList.Add (object value) 
    { 
     if (!value is string)) return -1; 
     return Add(value as string) 
    } 
} 

इस तरह के अंतर देखा जा सकता है:

StringCollection collection = new StringCollection(); 
    collection.Add(1); // compile error 
    (collection as IList).Add(1); // compiles, runtime error 
    (collection as IList).Add((object)"") // calls interface method, which adds string to collection 

परिशिष्ट क्यों इस पैटर्न लागू किया गया है

ऊपर को संबोधित नहीं करता कार्यान्वयन कुछ इस तरह जैसे लगते हैं हो सकता है। सी # भाषा विनिर्देश कहा गया है कि [§13.4.1, जोर जोड़ा]:

In some cases, the name of an interface member may not be appropriate for the implementing class, in which case the interface member may be implemented using explicit interface member implementation. [...]

It is not possible to access an explicit interface member implementation through its fully qualified name in a method invocation, property access, or indexer access. An explicit interface member implementation can only be accessed through an interface instance, and is in that case referenced simply by its member name.

StringCollection आवश्यक IList के व्यवहार का पालन करता है - IList कोई गारंटी नहीं है कि किसी भी मनमाने ढंग से वस्तु इसे करने के लिए जोड़ा जा सकता है बनाता है। स्ट्रिंगकोलेक्शन मजबूत गारंटी देता है - मुख्य रूप से, इसमें केवल तार होंगे। कक्षा में Add, Contains, Item, और अन्य मानक उपयोग केस के लिए अपनी दृढ़ता से टाइप की गई विधियां शामिल हैं जहां इसे IList के बजाय StringCollection के रूप में उपयोग किया जाता है। लेकिन यह अभी भी IList के रूप में पूरी तरह से अच्छी तरह से काम करता है, ऑब्जेक्ट को स्वीकार और वापस कर रहा है, लेकिन एक स्ट्रिंग नहीं है, तो एक आइटम जोड़ने के लिए एक त्रुटि कोड (IList परमिट के रूप में) लौट रहा है।

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

+0

तो मुझे याद रखना चाहिए कि एक इंटरफेस के अंगूठे के स्पष्ट कार्यान्वयन के नियम के रूप में कक्षा परिभाषाओं में निर्मित .NET पुस्तकालयों में दिखाई नहीं देता है? (क्योंकि मैं स्पष्ट रूप से स्ट्रिंगकोलेक्शन क्लास में सभी विधियों के बीच इस कार्यान्वयन को नहीं देख सकता) कोई कारण क्यों? –

+0

आम तौर पर, सदस्य छाया के समान प्रभाव में - मैंने इसे संबोधित करने के लिए प्रतिक्रिया में संशोधन किया। – drf

0

आप .net 2.0+ उपयोग कर रहे हैं, मैं सिर्फ जेनरिक का प्रयोग करेंगे:

IList<string> list = new List<string>(); 

है कि आप सब कुछ आप चाहते हैं देना चाहिए।

0

IList.Add(object) तारों के अलावा पैरामीटर स्वीकार कर सकते हैं - यह किसी भी प्रकार को स्वीकार कर सकता है। इसलिए यदि आप स्ट्रिंग को स्वीकार करने के लिए इंटरफ़ेस के कार्यान्वयन की घोषणा करते हैं, तो यह अब इंटरफ़ेस विनिर्देश से मेल नहीं खाता है, क्योंकि अब मैं Stream में उदाहरण के लिए पास नहीं कर सका।

विचरण अन्य तरीका काम कर सकते हैं: यदि इंटरफ़ेस विधि तार को स्वीकार करने की घोषणा की गई है, तो स्वीकार कर ठीक वस्तुओं हो सकता है, के बाद से तार भी वस्तुओं, और इसलिए इंटरफेस की विधि के लिए किसी भी इनपुट भी स्वीकार्य इनपुट होगा आपका कार्यान्वयन (हालांकि, आपको अभी भी एक विधि को स्वीकार करने वाली विधि के साथ एक स्पष्ट इंटरफ़ेस कार्यान्वयन प्रदान करना होगा, क्योंकि सी # में एक इंटरफ़ेस विधि कार्यान्वयन इंटरफ़ेस विधि घोषणा से बिल्कुल सटीक रूप से मेल खाता है।)

0

मूल रूप से निर्दिष्ट करता है कि आप Add पर कॉल कर सकते हैं और किसी ऑब्जेक्ट को पैरामीटर के रूप में पास करें, बॉक्स किए गए Int से IList पर System.DivideByZeroException पर। यदि आप केवल Add(string) विधि प्रदान करते हैं, तो आपने यह आवश्यकता पूरी नहीं की है क्योंकि आप केवल स्ट्रिंग जोड़ सकते हैं।

दूसरे शब्दों में, आप StringCollection.Add(new Object()); पर कॉल नहीं कर पाएंगे, जो इंटरफ़ेस को ठीक से लागू किया गया था, जो पूरी तरह से करने योग्य होना चाहिए।: डी

संबंधित मुद्दे