2012-03-13 9 views
27

अंतिम लाइन की अनुमति क्यों नहीं है?क्यों नहीं IENumerable <struct> IENumerable <object> के रूप में डाला जा सकता है?

IEnumerable<double> doubleenumerable = new List<double> { 1, 2 }; 
IEnumerable<string> stringenumerable = new List<string> { "a", "b" }; 
IEnumerable<object> objects1 = stringenumerable; // OK 
IEnumerable<object> objects2 = doubleenumerable; // Not allowed 

ऐसा इसलिए है क्योंकि डबल एक मान प्रकार है जो ऑब्जेक्ट से प्राप्त नहीं होता है, इसलिए कॉन्वर्सिस काम नहीं करता है?

मतलब है कि है इस काम करने के लिए कोई रास्ता नहीं है कि वहाँ:

public interface IMyInterface<out T> 
{ 
    string Method(); 
} 

public class MyClass<U> : IMyInterface<U> 
{ 
    public string Method() 
    { 
     return "test"; 
    } 
} 

public class Test 
{ 
    public static object test2() 
    { 
     IMyInterface<double> a = new MyClass<double>(); 
     IMyInterface<object> b = a; // Invalid cast! 
     return b.Method(); 
    } 
} 

और मैं लिखने की ज़रूरत है कि मेरे बहुत ही IMyInterface<T>.Cast<U>() कि करना है?

+0

संभावित डुप्लिकेट [क्यों covariance और contravariance मूल्य प्रकार का समर्थन नहीं करते हैं] (http://stackoverflow.com/questions/12454794/why-covariance-and-contravariance-do-not-support-value-type) – nawfal

उत्तर

44

अंतिम पंक्ति की अनुमति क्यों नहीं है?

क्योंकि डबल एक मान प्रकार है और ऑब्जेक्ट एक संदर्भ प्रकार है; कॉन्वर्सिस केवल तभी काम करता है जब दोनों प्रकार संदर्भ प्रकार हैं।

ऐसा इसलिए है क्योंकि डबल एक मान प्रकार है जो ऑब्जेक्ट से प्राप्त नहीं होता है, इसलिए कॉन्वर्सिस काम नहीं करता है?

नहीं। वस्तु वस्तु से प्राप्त होती है। ऑब्जेक्ट से प्राप्त सभी मान प्रकार।

अब सवाल आपसे पूछा जाना चाहिए था:

क्यों सहप्रसरण IEnumerable<object> को IEnumerable<double> कन्वर्ट करने के लिए काम नहीं करता है?

क्योंकि मुक्केबाजी कौन करता है? डबल से ऑब्जेक्ट में रूपांतरण बॉक्स डबल होना चाहिए। मान लीजिए कि आपके पास IEnumerator<object>.Current पर कॉल है जो IEnumerator<double>.Current के कार्यान्वयन के लिए "वास्तव में" एक कॉल है। कॉलर किसी ऑब्जेक्ट को वापस आने की अपेक्षा करता है। कैली एक डबल देता है। कोडिंग कहां है जो मुक्केबाजी निर्देश करता है जो डबल बॉक्स को IEnumerator<double>.Current द्वारा बॉक्स किए गए डबल में लौटाता है?

यह कहीं भी है, और यही कारण है कि यह रूपांतरण अवैध है। Current पर कॉल मूल्यांकन स्टैक पर आठ-बाइट डबल डालने जा रहा है, और उपभोक्ता मूल्यांकन स्टैक पर एक बॉक्स किए गए डबल के चार-बाइट संदर्भ की उम्मीद कर रहा है, और इसलिए उपभोक्ता क्रैश होने जा रहा है और बहुत मर जाएगा एक misaligned ढेर और अमान्य स्मृति के संदर्भ के साथ।

आप कोड के बक्से को अंजाम कि तो यह कुछ बिंदु पर लिखा हो गया है, और आप व्यक्ति ने इसे लिखने के लिए हो जाता है कर रहे हैं चाहते हैं।

IEnumerable<object> objects2 = doubleenumerable.Cast<object>(); 

अब आप एक सहायक विधि है कि मुक्केबाजी अनुदेश कि एक आठ बाइट के लिए एक संदर्भ के लिए डबल से डबल धर्मान्तरित होता है कहते हैं: सबसे आसान तरीका है Cast<T> विस्तार विधि का उपयोग करने के लिए है।

अद्यतन: एक टिप्पणीकर्ता नोट करता है कि मैंने इस सवाल का आग्रह किया है - यानी, मैंने एक तंत्र के अस्तित्व को पूर्ववत करके एक प्रश्न का उत्तर दिया है जो मूल प्रश्न के समाधान के रूप में हर समस्या को हल करता है। Cast<T> के कार्यान्वयन को जानने के लिए समस्या का समाधान कैसे किया जाता है या नहीं?

यह इस स्केच की तरह काम करता है। ध्यान दें कि पैरामीटर प्रकार नहीं सामान्य हैं:

public static IEnumerable<T> Cast<T>(this IEnumerable sequence) 
{ 
    if (sequence == null) throw ... 
    if (sequence is IEnumerable<T>) 
     return sequence as IEnumerable<T>; 
    return ReallyCast<T>(sequence); 
} 

private static IEnumerable<T> ReallyCast<T>(IEnumerable sequence) 
{ 
    foreach(object item in sequence) 
     yield return (T)item; 
} 

निर्धारित करता है कि टी करने के लिए वस्तु से डाली एक unboxing रूपांतरण है या एक संदर्भ रूपांतरण क्रम के लिए स्थगित किया जाता है के लिए जिम्मेदारी। जिटर जानता है कि टी संदर्भ प्रकार या मूल्य प्रकार है या नहीं। 99% समय निश्चित रूप से एक संदर्भ प्रकार होगा।

+6

बंद विषय, लेकिन मेरी इच्छा है कि आप ट्वीट करें। – Joe

+1

1+ पोस्टिंग के साथ सामान्य रूप से तेज़ी से। मुझे पसंद है "तो उपभोक्ता दुर्घटनाग्रस्त होने जा रहा है और एक गलत तरीके से ढेर और अवैध स्मृति के संदर्भ के साथ मर जाएगा" भाग। –

+17

@ जोउत्स्कन: जब मेरे पास कुछ कहना है जो 120 वर्णों में फिट बैठता है और सामान्य हित में है, तो मैं करूँगा। एक लंबी प्रतीक्षा की उम्मीद है। –

4

यह समझने के लिए कि क्या अनुमति है और अनुमति नहीं है, और क्यों चीजें व्यवहार करती हैं, यह समझने में मददगार है कि हुड के नीचे क्या चल रहा है। प्रत्येक मान प्रकार के लिए, एक समान प्रकार की क्लास ऑब्जेक्ट मौजूद होती है, जो - सभी ऑब्जेक्ट्स की तरह - System.Object से प्राप्त होगी। प्रत्येक वर्ग ऑब्जेक्ट में इसके डेटा के साथ 32-बिट शब्द (x86) या 64-बिट लांगवर्ड (x64) होता है जो इसके प्रकार की पहचान करता है। मूल्य-प्रकार भंडारण स्थान, हालांकि, उन वर्ग वस्तुओं या संदर्भों को उनके पास नहीं रखते हैं, न ही उनके पास उनके साथ संग्रहीत प्रकार का डेटा है। इसके बजाय, प्रत्येक आदिम-मूल्य-प्रकार स्थान केवल मूल्य का प्रतिनिधित्व करने के लिए आवश्यक बिट्स रखता है, और प्रत्येक संरचना-मूल्य-प्रकार भंडारण स्थान में उस प्रकार के सभी सार्वजनिक और निजी क्षेत्रों की सामग्री होती है।

एक प्रतियां प्रकार Object से एक के लिए प्रकार Double के एक चर, एक वर्ग-वस्तु है कि नया वर्ग वस्तु को मूल से Double और प्रतियां सभी बाइट्स के साथ जुड़े प्रकार का एक नया उदाहरण बनाता है। यद्यपि बॉक्स किए गए- Double वर्ग प्रकार का नाम Double मान प्रकार के समान है, इससे अस्पष्टता नहीं होती है क्योंकि आम तौर पर उन्हें समान संदर्भों में उपयोग नहीं किया जा सकता है। मूल्य प्रकारों के संग्रहण स्थानों में संग्रहित प्रकार की जानकारी के बिना, कच्चे बिट्स या फ़ील्ड के संयोजन होते हैं; इस तरह के एक भंडारण स्थान की प्रतिलिपि सभी बाइट्स की प्रतिलिपि बनाते हैं, और इसके परिणामस्वरूप सभी सार्वजनिक और निजी क्षेत्रों की प्रतिलिपि बनाई जाती है। इसके विपरीत, मूल्य प्रकारों से व्युत्पन्न प्रकारों की ढेर वस्तुओं ढेर वस्तुओं हैं, और ढेर वस्तुओं की तरह व्यवहार करते हैं। हालांकि सी # मूल्य-प्रकार भंडारण स्थानों की सामग्री का सम्मान करता है, भले ही वे Object के डेरिवेटिव हैं, हुड के तहत इस तरह के स्टोरेज स्थानों की सामग्री केवल प्रकार के सिस्टम के बाहर प्रभावी ढंग से बाइट्स का संग्रह है। चूंकि उन्हें केवल कोड द्वारा एक्सेस किया जा सकता है, जो जानता है कि बाइट्स क्या दर्शाते हैं, ऐसी जानकारी को भंडारण स्थान के साथ ही स्टोर करने की आवश्यकता नहीं है। हालांकि GetType को किसी संरचना पर कॉल करते समय मुक्केबाजी की आवश्यकता को अक्सर GetType के मामले में वर्णित किया गया है, जो गैर-छायांकित, गैर-वर्चुअल फ़ंक्शन होने के कारण वास्तविक वास्तविकता इस तथ्य से उत्पन्न होती है कि मूल्य-प्रकार भंडारण स्थान की सामग्री (जैसा कि से अलग है स्थान स्वयं) प्रकार की जानकारी नहीं है।

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