2009-11-20 4 views
8

यह संकलित क्यों नहीं करता है?मैं कंक्रीट प्रकारों की सूची को उस ठोस इंटरफ़ेस की सूची में क्यों निर्दिष्ट नहीं कर सकता?

public interface IConcrete { } 

public class Concrete : IConcrete { } 

public class Runner 
{ 
    public static void Main() 
    { 
     var myList = new List<Concrete>(); 
     DoStuffWithInterfaceList(myList); // compiler doesn't allow this 
    } 

    public static void DoStuffWithInterfaceList(List<IConcrete> listOfInterfaces) { } 

} 

और तेज तरीका सही प्रकार पर MyList पाने के लिए क्या है?

संपादित मैं DoStuffWithInterfaceList उदाहरण

उत्तर

10

स्वीकृत समाधान बड़ी सूचियों के लिए काफी अक्षम है, और पूरी तरह से अनावश्यक है। आप कभी तो थोड़ा बिना कोई भी रूपांतरण कोड काम बनाने के लिए, या तो अस्पष्ट या स्पष्ट अपने विधि के हस्ताक्षर बदल सकते हैं:

public class Runner 
{ 
    public static void Main() 
    { 
     var myList = new List<Concrete>(); 
     DoStuffWithInterfaceList(myList); // compiler doesn't allow this 
    } 

    public static void DoStuffWithInterfaceList<T>(List<T> listOfInterfaces) 
     where T: IConcrete 
    { } 
} 

सूचना है कि विधि अब सामान्य है और यह सुनिश्चित करना है कि यह एक प्रकार बाधा का उपयोग करता है केवल IConcrete उपप्रकारों की सूचियों के साथ बुलाया जा सकता है।

+0

(वैसे: चूंकि उपर्युक्त समाधान हमेशा ऐसे परिदृश्यों में काम करता है, सी # 4 में जेनेरिक कॉन्वर्सिस का परिचय केवल ओवरकिल साबित हो सकता है) –

+0

मैन, जो वास्तव में स्पष्ट है । धन्यवाद। – JeremyWeir

2

सी # वर्तमान में इस तरह सामान्य प्रकार परिवर्तित ( यह, सी # 4 में समर्थन किया जाएगा अगर मैं इसे सही ढंग से रूप wcoenen राज्यों टिप्पणी में नीचे को समझने का समर्थन नहीं करता में गड़बड़, और एरिक अपने जवाब में भी स्पष्ट करता है, इसे सी # 4 में काम करने का एकमात्र तरीका IEnumerable<IConcrete> का उपयोग करना है)। अभी के लिए आपको अपनी सूची को किसी भी तरह से परिवर्तित करने की आवश्यकता होगी। स्पष्टता के लिए भले ही मैं इन सबसे छुटकारा पाना तरह

DoStuffWithInterface(myList.ConvertAll<IConcrete>(n => n as IConcrete)); 

अद्यतन
मैंने महसूस किया कि आप शायद लैम्ब्डा के अंदर डाली जरूरत नहीं है,:

आप इस तरह विधि कह सकते हैं। तो यह भी काम करना चाहिए:

DoStuffWithInterface(myList.ConvertAll<IConcrete>(n => n)); 
+0

मुझे पता है, मैंने उदाहरण को गड़बड़ कर दिया, मेरा मतलब है कि यह सभी सूचियों पर काम करता है, मेरा संपादन देखें। धन्यवाद। – JeremyWeir

+0

ठीक है, मैंने तदनुसार मेरा जवाब संपादित किया: ओ) –

+0

निश्चित रूप से सी # 4 इसे या तो अनुमति नहीं देता है, क्योंकि अन्यथा DoStuffWithInterface * किसी भी * 'IConcrete' कार्यान्वयन को उस सूची में सम्मिलित करने में सक्षम होगा जो वास्तव में केवल 'कंक्रीट' उदाहरणों। एरिक का मतलब है 'सूची ' 'कॉन्वेंट "नहीं है। –

0
foreach (var item in myList) 
    DoStuffWithInterface(item); 

या

public void DoStuffWithInterface(IList<IConcrete> concrete) { } 

या

var myNewList = myList.Cast<IConcrete>(); 
+0

क्या यह केवल सी # 4 में काम करने जा रहा है? – JeremyWeir

+0

ओह हाँ यह काम नहीं कर सकता .... –

1

आप की कोशिश कर सकते

public void DoStuffWithInterface(IList<IConcrete> concrete) { } 

लेकिन मुझे लगता है कि यह केवल .NET 4.0 में काम करता है।

आप चाहते हैं गंदा हो, तो बस

public void DoStuffWithInterface(IList concrete) { } 

करते हैं और अगर वस्तुओं बाहर आ ठोस हैं देखने के लिए जाँच।

2

इसे कॉन्वर्स और contravariance के साथ करना है। एरिक लिपर्ट ने इस साल की शुरुआत में इसके बारे में बहुत कुछ लिखा था। (विशेष रूप से उस विषय पर 11 ब्लॉग प्रविष्टियां।) पहला वाला Covariance and Contravariance in C#, Part One है। इसे पढ़ें और उनके ब्लॉग को बाकी के लिए खोजें। वह विस्तृत स्पष्टीकरण प्रदान करता है कि इस तरह की चीज क्यों मुश्किल है।

अच्छी खबर: कुछ प्रतिबंध सी # 4.0 में उठाए गए हैं।

4

वर्तमान में, यह वर्जित है क्योंकि अन्यथा प्रकार की सुरक्षा टूट जाएगी। आप DoStuffWithInterfaceList के इस अंदर की तरह कुछ कर सकता है:

public class OtherConcrete : IConcrete { } 

public void DoStuffWithInterfaceList(List<IConcrete> listOfInterfaces) 
{ 
     listOfInterfaces.Add(new OtherConcrete()); 
} 

कौन सा रन टाइम पर विफल हो जाएगा क्योंकि listOfInterfaces प्रकार कंक्रीट केवल की है।

जैसा कि अन्य ने कहा, यह संभव होगा जब तक कि आप विधि के अंदर सूची नहीं बदलते हैं, लेकिन आपको इसे संकलक को स्पष्ट रूप से बताना होगा।

सूची बदलने के बारे में अपने अन्य प्रश्न का उत्तर देने के लिए, यदि आप .NET 3.5 का उपयोग कर रहे हैं तो मैं संख्यात्मक .Cast <> एक्सटेंशन विधि के साथ जाऊंगा। अन्यथा, आप उपज कीवर्ड का उपयोग करके आलसी रूपांतरण विधि स्वयं लिख सकते हैं, जो आपको वही प्रभाव देगा।

संपादित करें:

के रूप में एरिक Lippert कहा, तुम क्रम में IEnumerable का उपयोग करना चाहिए उस में काम करने के लिए सी # 4.

2

IList कार्य नहीं करेगा क्योंकि IList contravariant नहीं है। इसे IENumerable होने की आवश्यकता है हालांकि फिर यह केवल 4.0 में काम करता है। आप लैम्बडा अभिव्यक्ति के साथ एक कन्वर्टएल का भी उपयोग कर सकते हैं और यह 3.5

16

लगभग सभी उत्तरों का कहना है कि यह सी # 4 में समर्थित होगा। वे सभी गलत हैं।

बस क्रिस्टल स्पष्ट होने के लिए: यह covariance का एक उदाहरण नहीं है कि हम सी # 4 में समर्थन करेंगे, क्योंकि ऐसा करने से टाइपएफ़ नहीं होगा। हम टाइपएफ़ कॉन्वर्सिस और जेनेरिक इंटरफेस और प्रतिनिधियों के contravariance का समर्थन कर रहे हैं जो संदर्भ प्रकार तर्क के साथ निर्मित हैं। यहां उदाहरण एक वर्ग प्रकार, सूची का उपयोग करता है, एक इंटरफ़ेस प्रकार नहीं। और इंटरफ़ेस प्रकार, IList, covariance या contravariance के लिए टाइपएफ़ नहीं है।

आईन्यूमेरेबल कॉन्वेंटेंट होगा, क्योंकि यह एक इंटरफेस है जो कॉन्वर्सिस के लिए सुरक्षित है।

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

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