2010-07-27 12 views
5

मुझे पता चला कि कंक्रीट ऑब्जेक्ट्स की एक सूची इंटरफ़ेस ऑब्जेक्ट की सूची में नहीं जोड़ा जा सकता है।सूची <IJob> .ddRange (सूची <Job>) काम नहीं करता

public static void AddJob(List<IJob> masterJobs, List<Job> jobs) 
{ 
    masterJobs.AddRange(jobs.Cast<IJob>()); 
} 

इसके पीछे तर्कसंगत क्या है:

public static void AddJob(List<IJob> masterJobs, List<Job> jobs) 
{ 
    masterJobs.AddRange(jobs); //fail to compile 
} 

इसके बजाय, एक निम्नलिखित कोड का उपयोग करने की जरूरत है?

+5

स्कीट + कॉन्वर्सिस/contravariance तीन में ... दो ... एक ... – Will

+0

काम करेगा यदि आप सी # 4.0 –

+1

का उपयोग करने में सक्षम हैं, तो मुझे लगता है कि '// संकलित करने में असफल' टिप्पणी ऊपर दूसरा उदाहरण पहले से बाएं से अधिक है? या वह भी संकलन करने में विफल रहता है? –

उत्तर

10

लास सही है कि यह सी # 3 में क्यों काम नहीं करेगा - List<IJob> से List<Job> पर कोई रूपांतरण नहीं है।

सी # 4 में यह सूची की वजह से काम नहीं करेगा, क्योंकि IEnumerable<T> कॉन्वर्सेंट है। तो दूसरे शब्दों में, कोड को प्रभावी ढंग से होगा:

public static void AddJob(List<IJob> masterJobs, List<Job> jobs) 
{ 
    IEnumerable<IJob> jobsTmp = jobs; // This is the covariance working 
    masterJobs.AddRange(jobs); // This is now fine 
} 

jobsIEnumerable<Job> लागू करता है, तो IEnumerable<IJob> के लिए एक संदर्भ रूपांतरण सहप्रसरण के माध्यम से देखते है, तो यह सब ठीक काम करता है। Cast<T> पर कॉल प्रभावी ढंग से आपके सी # 3 वर्कअराउंड में एक समान काम कर रहा है - आप इसे IEnumerable<IJob> में बदलने के लिए उपयोग कर रहे हैं।

यदि आप जेनेरिक भिन्नता के बारे में अधिक जानना चाहते हैं, तो video of my NDC 2010 talk उपलब्ध है, या एरिक लिपर्ट के series of blog posts पर इसे पढ़ें।

+0

तो, मुझे इस सीधे वे 'इस्तेमाल किया in' और' out' विपरीत/सहप्रसरण सूचित करने के लिए है क्योंकि यह अनिवार्य रूप से उस वर्ग * केवल * सामान्य प्रकार का एक उदाहरण "में लेता है" (यानी, एक विधि का वर्णन करते हैं ... तर्क) या यदि वर्ग * केवल * कक्षा के एक उदाहरण (यानी, एक विधि का वापसी मूल्य) पास करता है? IEnumerable किसी भी टी के नहीं "में ले" है, इसलिए यह के रूप में वर्ग को चिह्नित करने के लिए सुरक्षित है और इसलिए सामान्य प्रकार covariant है? IList दोनों टी में लेते हैं और टी बाहर निकलते हैं, जो इसे परिवर्तनीय बनाता है? – Will

+0

@Will: हाँ, यह बिल्कुल सही है। बहुत अधिक जानकारी के लिए भिन्नता के बारे में एरिक लिपर्ट की ब्लॉग पोस्ट श्रृंखला देखें। मैं अपनी पोस्ट को लिंक करने के लिए संपादित करूंगा। –

+0

जॉर्ज द्वारा, मुझे लगता है कि मुझे मिल गया है! मुझे लगता है मुझे मिल गया है! (क्यू संगीत संख्या) – Will

8

कारण यह है कि एक List<IJob> एक List<Job>, हालांकि एक Job लागू करता IJob नहीं है।

इस सह या विपरीत विचरण है (। मुझे याद है कभी नहीं है जो जो)

सोच चला जाता है कुछ इस तरह:

संकलक गारंटी नहीं दे सकते कि AddRange केवल पैरामीटर से बाहर बातें पढ़ता है यह दिया जाता है, और इस प्रकार यह गारंटी नहीं दे सकता कि यह सुरक्षित है, और इस प्रकार यह संकलन करने में विफल रहता है।

उदाहरण के लिए, के लिए सभी संकलक जानता है, AddRange किसी अन्य वस्तु jobs पैरामीटर में जोड़ सकता है, को लागू करने वाली IJob (क्योंकि AddRange IJob संग्रह की उम्मीद है), लेकिन Job नहीं है, जो है क्या उम्मीद jobs, और इस तरह है कि होगा सुरक्षित नहीं है।

सी # 4.0 में, इसे संभालने के लिए कुछ समर्थन है, लेकिन मुझे यकीन नहीं है कि यह आपके विशेष मामले को संभालेगा क्योंकि समर्थन को इंटरफ़ेस-स्तर पर निर्दिष्ट किया जाना चाहिए, न कि विधि-स्तर पर।

दूसरे शब्दों में, आपको इंटरफ़ेस प्रकार पर निर्दिष्ट करना होगा कि टी से संबंधित सभी चीजें केवल संग्रह में जा रही हैं, कभी भी इससे बाहर नहीं, और फिर संकलक आपको ऐसा करने की अनुमति देगा। हालांकि, एक संग्रह जिसे आप पढ़ नहीं सकते हैं वह काफी व्यर्थ होगा।

+1

"आउट" कॉन्वर्सिस है और "इन" contravariance है; अब यह 'IList ' और इसलिए कॉन्वेंटेंट है। (और मैं उस पर गलत हूँ, नीचे देखें) – Will

+0

ऊह, अच्छा, नहीं लगता कि मुझे लगता है कि देखा है पहले दो से कम एक सारांश है, धन्यवाद! –

+0

यह आदमी 4.0 में सहप्रसरण और contravariance जेनरिक समर्थन के बारे में अच्छा विस्तार में चला जाता है: http://www.buunguyen.net/blog/new-features-of-csharp-4.html – Will

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