2012-09-11 28 views
8

मुझे .NET जेनेरिक प्रकार कास्टिंग में कुछ नहीं मिलता है। क्या कोई बता सकता है कि निम्न कोड स्निपेट में क्या होता है?जेनेरिक प्रकार कास्टिंग

void Main() 
{ 
    IEnumerable<int> ints = new List<int>(); 
    IEnumerable<string> strings = new List<string>(); 

    var rez1=(IEnumerable<object>)ints; //runtime error 
    var rez2=(IEnumerable<object>)strings; //works 
    var rez3=(List<object>)strings; //runtime error 
} 

उत्तर

11

की दूसरी लाइन जो सबसे आसान है के साथ शुरू करते हैं।

यही काम करता है डाली क्योंकि IEnumerable<T> के प्रकार के पैरामीटर अब covariant है (कि क्या out T में out करता है)। इसका मतलब है कि आप IEnumerable<Derived> को IEnumerable<Base> पर स्वतंत्र रूप से डाल सकते हैं।

पहली पंक्ति, जो एक ही मामला प्रतीत होता है, काम नहीं करता है क्योंकि int एक मान प्रकार है। इंटरफेस भिन्नता मूल्य प्रकारों के साथ बिल्कुल काम नहीं करती है क्योंकि मूल्य प्रकार वास्तव में System.Object से प्राप्त नहीं होते हैं; वे को object में बॉक्स किया जा सकता है, लेकिन यह वही नहीं है। दस्तावेज में उल्लेख किया गया है कि

भिन्नता केवल संदर्भ प्रकारों पर लागू होती है; यदि आप एक प्रकार प्रकार को एक प्रकार प्रकार पैरामीटर के लिए निर्दिष्ट करते हैं, तो टाइप पैरामीटर परिणामस्वरूप निर्मित प्रकार के लिए invariant है।

अंत में, तीसरी लाइन काम नहीं करता क्योंकि List<T> के प्रकार के पैरामीटर अपरिवर्तनीय है। आप देख सकते हैं कि out इसके प्रकार पैरामीटर पर नहीं है; नियमों की अनुमति नहीं देने कि क्योंकि List<T> एक इंटरफेस नहीं है:

.NET फ्रेमवर्क 4 में, संस्करण प्रकार पैरामीटर जेनेरिक इंटरफेस और सामान्य प्रतिनिधि प्रकार तक ही सीमित हैं। एक भंडारण-स्थान प्रकार एक ढेर ऑब्जेक्ट प्रकार, और:

+0

लेकिन Int32 ऑब्जेक्ट में डाला जा सकता है। क्या यह एक संवेदना बनाने के लिए पर्याप्त नहीं है? या यह एक कंपाइलर सुविधा है? – Vasaka

+0

@ वासाका: यह एक मुक्केबाजी ऑपरेशन है और एक संदर्भ रूपांतरण नहीं है। यह तकनीकी है, लेकिन समान वाक्यविन्यास के बावजूद प्रत्येक मामले में वास्तव में संकलक वास्तव में क्या करता है। – Jon

+0

... सभी सामान्य वर्गों और structs के प्रकार पैरामीटर के रूप में हैं; इंटरफ़ेस और प्रतिनिधि प्रकारों के लिए केवल भिन्नता का प्रकार टाइप किया जा रहा है। – phoog

2

ऐसा इसलिए है क्योंकि इंटरफ़ेस कॉन्वर्सिस केवल संदर्भ प्रकारों के साथ काम करता है। Int32, ज़ाहिर है, एक मूल्य प्रकार है।

यह और अधिक जानकारी देता है: http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx

और इसलिए यह करता है: http://ericlippert.com/2011/09/19/inheritance-and-representation/

0

हर प्रकार जो System.ValueType से निकला है, System.Enum के अपवाद के साथ की परिभाषा, वास्तव में चीजों के दो प्रकार परिभाषित करता है। उत्तरार्द्ध के उदाहरणों को स्पष्ट रूप से पूर्व में परिवर्तित किया जा सकता है (उसमें निहित डेटा की एक प्रति बनाते हुए), और पूर्व के उदाहरण स्पष्ट रूप से उत्तरार्द्ध (इसी तरह) के लिए टाइपकास्ट हो सकते हैं; भले ही दोनों प्रकार की चीजें उसी System.Type द्वारा वर्णित की गई हों, और हालांकि उनके पास एक ही सदस्य हैं, वे बहुत अलग व्यवहार करते हैं।

List<AnyClassType> ढेर-ऑब्जेक्ट संदर्भों का एक समूह पकड़ने की उम्मीद करेगा; चाहे प्रश्न में सूची List<String>, List<StringBuilder>, List<Button>, या जो भी हो, सूची के उपयोगकर्ताओं के लिए ब्याज हो, लेकिन List<T> के लिए वास्तव में रुचि नहीं है। यदि कोई List<Button> को IEnumerable<Control> पर रखता है, तो कोई व्यक्ति जो GetEnumerator() विधि को कॉल करता है, वह उस ऑब्जेक्ट को प्राप्त करने की अपेक्षा करेगा जो Control से प्राप्त ढेर ऑब्जेक्ट्स के आउटपुट संदर्भों को संदर्भित करेगा; List<Button>.GetEnumerator() से वापसी उस उम्मीद को पूरा करेगी।इसके विपरीत, अगर किसी को List<Int32>List<Object> पर डालना था, तो GetEnumerator() नामक कोई व्यक्ति उस चीज की अपेक्षा करेगा जो ढेर ऑब्जेक्ट संदर्भों को आउटपुट करेगा, लेकिन List<Integer>.GetEnumerator इसके बजाय मूल्य-प्रकार पूर्णांक आउटपुट करने वाली कुछ चीज़ों को उत्पन्न करेगा।

Int32 मानों को List<Object> या List<ValueType> में संग्रहीत करना संभव है; ऐसी सूची में एक पूर्णांक संग्रहीत करने से इसे अपने ढेर ऑब्जेक्ट फॉर्म में बदल दिया जाएगा और इसके संदर्भ में स्टोर किया जाएगा; कॉलिंग GetEnumerator() कुछ ऐसी चीज उत्पन्न करेगी जो ढेर संदर्भों को आउटपुट करे। हालांकि, निर्दिष्ट करने का कोई तरीका नहीं है कि ऐसी सूची में केवल Int32 से संबंधित हीप प्रकार के उदाहरण होंगे। सी ++/सीएलआई में, "हेप-संग्रहीत वैल्यूटाइप के संदर्भ" प्रकार के चर घोषित करना संभव है, लेकिन जेनेटिक प्रकारों के पीछे तंत्र इस प्रकार के साथ काम नहीं कर सकते हैं।