C#

2010-10-27 15 views
18

में covariance सी # 4.0 में List<Subclass> से List<Superclass> डालना संभव है?C#

इन पंक्तियों के साथ कुछ:

class joe : human {} 

List<joe> joes = GetJoes(); 

List<human> humanJoes = joes; 

यह है कि क्या सहप्रसरण के लिए है नहीं है?

आप कर सकते हैं यदि:

human h = joe1 as human; 

क्यों नहीं आप की तुलना में यह (जो) मनुष्यों [0] क्योंकि ऐसा करने के लिए कानूनी नहीं होगा

List<human> humans = joes as List<human>; 

ऐसा करने में सक्षम होना चाहिए वस्तु को नीचे गिरा दिया गया है .. और हर कोई खुश होगा। अब एकमात्र विकल्प एक नई सूची बनाना है

+2

यह मूलतः एक ही रूप में [सी # में, क्यों एक सूची वस्तु एक सूची चर में संग्रहीत नहीं किया जा सकता है] (है http://stackoverflow.com/questions/6557/इन-सी क्यों-नहीं कर सकते-ए-liststring-वस्तु होने वाली संग्रहीत में एक-listobject-चर)। –

+0

क्योंकि 'इंसान' तब 'सूची ' के उदाहरण का जिक्र करेंगे, जो @ जॉन के उदाहरण में दिखाए गए समस्याओं का कारण बनेंगे। –

+0

हाँ, उदाहरण को सही करने के बाद मुझे यह मिला .. समझ में आता है –

उत्तर

25

आप ऐसा नहीं कर सकते क्योंकि यह सुरक्षित नहीं होगा:

+0

के माध्यम से अच्छी तरह से मानव जो मानव की एक सूची है, इसलिए आपको इससे जोड़ी अतिरिक्त करने का प्रयास नहीं करना चाहिए (या सक्षम)। लेकिन प्रत्येक जो एक इंसान है, इसलिए इसे सुरक्षित रूप से सबक्लास में डालने के लिए सुरक्षित होना चाहिए। –

+0

आप निश्चित रूप से मानव एच = जोसलिस्ट [0] मानव के रूप में कर सकते हैं .. और यही वह है जिसे मैं ढूंढ रहा/पूछ रहा था .. पूरे सूची स्तर पर स्वीकार करें –

+0

@ सोनिक: आप अतिरिक्त 'जो' क्यों नहीं जोड़ेंगे या इसके लिए 'फ्रेड'? * वह * भिन्नता का प्रकार * हमेशा * स्वीकार्य है। इसे आज़माएं: 'सूची सूची = नई सूची (); सूची। जोड़ें ("यह एक स्ट्रिंग है)"; '। आप असफल होने की उम्मीद क्यों करेंगे? –

2

नहीं। सी # 4.0 की सह/contravariance विशेषताएं केवल इंटरफेस और प्रतिनिधियों का समर्थन करते हैं। List<T> जैसे ठोस प्रकारों का समर्थन नहीं करते हैं। ,

List<human> humanJoes = new List<human>(joes); 
+0

http://stackoverflow.com/questions/245607/how-is-generic-covariance-contra-variance-implemented-in-c-4-0 –

+0

इसलिए मुझे प्रत्येक जो के लिए मानव के रूप में लूप करना और नई वस्तु बनाना होगा और नई सूची में जोड़ना होगा? यही एकमात्र विकल्प है? –

+1

'IList ' के साथ यह संभव नहीं है, क्योंकि यह invariant है। –

6

एक नए मानव-सूची है कि इनपुट के रूप में Joes लेता इन्स्तांत। पर विचार करें:

List<Joe> joes = GetJoes();  
List<Human> humanJoes = joes; 
humanJoes.Clear(); 
humanJoes.Add(new Fred()); 
Joe joe = joes[0]; 

जाहिर आखिरी पंक्ति (नहीं करता है, तो पहले के एक एक) है विफल - के रूप में एक Fred एक Joe नहीं है। List<T> का आविष्कार पर इस गलती को संकलन समय के बजाय संकलित करता है।

1

नहीं। जैसा कि जेरेड ने कहा था, सी # 4.0 की सह/contravariance विशेषताएं केवल इंटरफेस और प्रतिनिधियों का समर्थन करते हैं। हालांकि यह IList<T> के साथ काम नहीं करता है, और कारण यह है कि IList<T> में सूची में आइटम जोड़ने और बदलने के तरीके शामिल हैं - जैसे जॉन स्कीट का नया जवाब कहता है।

एक ही तरीका है "जो" की एक सूची कास्ट करने के लिए करने के लिए "मानव" यदि इंटरफ़ेस विशुद्ध रूप से केवल पढ़ने के लिए है डिजाइन के द्वारा होता है, कुछ इस तरह सक्षम होने के लिए:

public interface IListReader<out T> : IEnumerable<T> 
{ 
    T this[int index] { get; } 
    int Count { get; } 
} 

यहां तक ​​कि एक Contains(T item) विधि होगा अनुमति नहीं है, क्योंकि जब आप IListReader<joe> से IListReader<human> पर कास्ट करते हैं, तो IListReader<joe> में कोई Contains(human item) विधि नहीं है।

आप "मजबूर" सकता IListReader<joe>, IListReader<human> या यहाँ तक कि IList<human> को IList<joe> से एक डाली एक GoInterface का उपयोग कर। लेकिन अगर सूची प्रतिलिपि करने के लिए काफी छोटी है, तो एक आसान समाधान यह है कि इसे सिर्फ नए List<human> में कॉपी करें, जैसा कि Paw ने बताया।

0

अगर मैं अपने List<Joe> joes के रूप में सामान्यीकृत करने के लिए जा ...

List<Human> humans = joes; 

... दो संदर्भों humans और joes, कर रहे हैं अब आगे, ठीक उसी सूची की ओर इशारा करते अनुमति देते हैं। उपर्युक्त असाइनमेंट के बाद दिए गए कोड में सूची में प्लंबर कहें, किसी अन्य प्रकार के इंसान के उदाहरण के सम्मिलन/जोड़ को रोकने का कोई तरीका नहीं है।यह देखते हुए कि class Plumber: Human {}

humans.Add(new Plumber()); // Add() now accepts any Human not just a Joe 

सूची है कि humans संदर्भित करता है के लिए अब दोनों Joes और प्लंबर शामिल हैं। ध्यान दें कि वही सूची ऑब्जेक्ट अभी भी संदर्भ joes द्वारा संदर्भित है। अब अगर मैं सूची ऑब्जेक्ट से पढ़ने के लिए संदर्भ joes का उपयोग करता हूं तो मैं एक जो की बजाय प्लंबर निकाल सकता हूं। प्लंबर और जो पूरी तरह से interconvertable होने के लिए जाना जाता है ... तो सूची से एक जोड़ी के बजाय प्लंबर की मेरी हो रही प्रकार की सुरक्षा टूट जाती है। जोस की सूची के संदर्भ में प्लंबर निश्चित रूप से स्वागत नहीं है।

हालांकि सी # के हाल के संस्करणों में, जेनेरिक इंटरफ़ेस को लागू करके एक सामान्य वर्ग/संग्रह के लिए इस सीमा के आसपास काम करना संभव है जिसका टाइप पैरामीटर out संशोधक है। मान लें कि अब हमारे पास ABag<T> : ICovariable<out T> है। आउट संशोधक टी को केवल आउटपुट स्थितियों तक सीमित करता है (उदा। विधि वापसी प्रकार)। आप बैग में किसी भी टी दर्ज नहीं कर सकते हैं। आप केवल उन्हें बाहर पढ़ सकते हैं। यह हमें प्लस डालने के बारे में चिंतित किए बिना ICovariable<Human> पर जोस को सामान्यीकृत करने की अनुमति देता है क्योंकि इंटरफ़ेस इसे अनुमति नहीं देता है। अब हम लिख सकते हैं ...

ICovariable<Human> humans = joes ; // now its good ! 
humans.Add(new Plumber()); // error