2010-09-27 11 views
12

संभव डुप्लिकेट की सूची में अशक्त नहीं जोड़ सकते:
Adding null to a List<bool?> cast as an IList throwing an exception.nullables

List<int?> listONullables = new List<int?>(); 
IList degenericed = listONullables; 

// This works fine 
listONullables.Add(null); 

// Run time exception: 
// "The value "" is not of type "System.Nullable`1[System.Int32]" 
// and cannot be used in this generic collection. Parameter name: value" 
degenericed.Add(null); 

// Also does not work. Same exception 
degenericed.Add((int?)null); 

// Also does not work 
// EDIT: I was mistaken, this does work 
degenericed.Add((int?)1); 

// Also does not work 
// EDIT: I was mistaken, this does work 
degenericed.Add(1); 

उपरोक्त कोड में टिप्पणियाँ देखें।

मैं इसके कारणों को समझता हूं (जब आप जेनेरिक को निकाल देते हैं तो रनटाइम सीमित जानकारी के साथ सबसे अच्छा कर सकता है)। मैं बस सोच रहा हूं कि इसके आसपास कोई रास्ता है, भले ही यह एक हैक का थोड़ा सा हो।

समस्या तब उत्पन्न हुई जब मैंने एक फ़ंक्शन के सामान्य संस्करण को गैर सामान्य संस्करण के रूप में एक ही निजी कार्यान्वयन का उपयोग करने का प्रयास किया, इसलिए यदि आवश्यक हो तो मैं इसके आसपास काम कर सकता हूं (दो बहुत समान कार्यान्वयन हैं), लेकिन स्पष्ट रूप से यह बेहतर है अगर मैं इसे समझ सकता हूं।

संपादित करें: मेरे द्वारा ऊपर की गई अंतिम दो प्रविष्टियां विफल नहीं हैं जैसे मैंने मूल रूप से कहा था। लेकिन पहले दो करते हैं। मैंने ऊपर दिए गए कोड में उस प्रभाव को टिप्पणियां जोड़ दी हैं।

+7

जब मैंने कोशिश की तो आपका कोड अपवाद के बिना पूरी तरह से मेरे लिए चला गया। –

+1

मैं दूसरे उदाहरण पर अपवाद की पुष्टि कर सकता हूं: '.dd ((int?) Null) ', .NET 3.5 – Aren

+1

2 सकारात्मक और 1 नकारात्मक के साथ, यह समय है कि सभी ने कंपाइलर संस्करण आदि का उल्लेख करना शुरू किया। –

उत्तर

5

टिप्पणी में चर्चा पर विस्तार से बता दें ऐसा लगता है कि 4.0 में List<T>.IList.Add में, वहाँ है:

ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item); 
try 
{ 
    this.Add((T) item); 
} 
catch (InvalidCastException) 
{ 
    ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T)); 
} 

और 2.0 VerifyValueType जो केवल IsCompatibleObject विधि की जाँच करता है है:

VerifyValueType(item); 

... 

private static bool IsCompatibleObject(object value) { 
    if((value is T) || (value == null && !typeof(T).IsValueType)) { 
     return true; 
    } 
    return false; 
} 

बाद में एक सरल फैशन में लिखा गया है। value टी नहीं है (क्योंकि शून्य Nullable<int>.HasValue = false जैसा नहीं है)। साथ ही, @LBushkin नोट्स के रूप में, टाइपऑफ (टी) IsValueType Nullable<int> के लिए सच हो जाएगा और दाएं हाथ की तरफ भी झूठी मूल्यांकन करता है।

+0

मुझे विश्वास है कि यहां समस्या यह है कि '! टाइपऑफ (टी) IsValueType' झूठ का मूल्यांकन करता है जब' टी' 'Nullable ' और 'मान टी है 'झूठी के लिए भी मूल्यांकन करता है। नतीजतन, चेक विफल रहता है, और आप इस कार्यान्वयन के माध्यम से एक शून्य जोड़ नहीं सकते हैं। .NET 4.0 कार्यान्वयन सामान्य रूप से सामान्य 'सूची पर प्रतिनिधि करता है।' कार्यान्वयन जोड़ें जो इस मामले को सही तरीके से संभालता है। – LBushkin

+0

@ एल बुशकिन, आप सही हैं, इसके लिए भी संबोधित करने की आवश्यकता है। अपडेट करूंगी। –

+0

@ किर्क: 'degenericed का उपयोग करें। जोड़ें (नया Nullable ())' यह भी विफल रहता है क्योंकि यह 'degenericed के बराबर है। जोड़ें ((int?) शून्य)'। अंतिम परिणाम 'जोड़ें' विधि में सादे 'शून्य' को पार करने के लिए अलग नहीं है। – LukeH

1

यह कोविरेन्स और contravariance के परिचय के साथ .NET 4.0 में काम करता है।

जब से तुम (रनटाइम त्रुटि के कारण स्पष्ट रूप से) 4.0 में नहीं हैं आप इसे चारों ओर डिफ़ॉल्ट (int) गुजर रहा एक शून्य मान

अद्यतन प्राप्त करने के लिए काम कर सकते हैं: मेरी बात सुनो मत करो डिफ़ॉल्ट (पूर्णांक) = 0 शून्य नहीं। मैं मंद हूँ :(

इस अशक्त के लिए काम करता है:?

degenericed.Add(default(int)); 

ऐड कॉल मेरे लिए ठीक से काम करता है, हालांकि लाइन बदलने के लिए

degenericed.Add(1); 
+0

मुझे नहीं लगता कि इसमें .NET 4 में भिन्न परिवर्तनों के साथ कुछ भी करना है - यह ढांचे के पुराने संस्करणों में बस एक बग है। – LukeH

0

कोशिश:

IList degenericed = listONullables; 

इस द्वारा:

IList<int?> degenericed = listONullables; 
2

यह 3.5 ढांचे में एक बग (और शायद पहले के संस्करणों भी) है। बाकी का उत्तर .NET 3.5 से संबंधित है, हालांकि टिप्पणियां बताती हैं कि बग ढांचे के संस्करण 4 में तय किया गया है ...

जब आप IList.Add विधि पर मान-प्रकार पास करते हैं तो इसे इंटरफ़ेस गैर-जेनेरिक होने के कारण object के रूप में बॉक्स किया जाएगा। इस नियम का एक अपवाद null निरर्थक प्रकार है जो सादे null में परिवर्तित (बॉक्स नहीं किए गए) हैं।

List<T> वर्ग चेक पर IList.Add विधि है कि जिस प्रकार को जोड़ने की कोशिश कर रहे वास्तव में एक T, लेकिन है संगतता की जाँच खाते में null नल प्रकार नहीं ले करता है:

जब आप null पारित , संगतता जांच जानता है कि आपकी सूची List<int?> है और जानता है कि int? एक मान-प्रकार है, लेकिन - यहां बग है - एक त्रुटि फेंकता है क्योंकि यह "जानता है" कि मान-प्रकार संभवतः null नहीं हो सकता है, null को मिटा दें जो आपने पारित किया है वह संभवतः int? नहीं हो सकता है ।

+0

वास्तव में यह '1' के लिए कोई त्रुटि नहीं फेंकता है। –

+0

@ किर्क: ओह, तय! – LukeH