2009-03-04 13 views
6

पर हाल ही में मुझे सी # में एक बहुत ही आश्चर्यजनक व्यवहार मिला। मेरे पास एक विधि थी जो पैरामीटर के रूप में IEnumerable<Object> लेती है और मैं IEnumerable<string> पास कर रहा था लेकिन यह संभव नहीं है। सी # में सबकुछ ऑब्जेक्ट पर उड़ाया जा सकता है, यह क्यों संभव नहीं है? यह मेरे लिए पूरी तरह भ्रमित है। कृपया मुझे इस मुद्दे पर मुझे साफ़ करें।IENumerable <Object> से IENumerable <string>

+0

यह कैसे संभव नहीं है? क्या यह एक ArgumentException फेंक रहा है? इसके अलावा, यदि आप इसे ऑब्जेक्ट के रूप में घोषित करने जा रहे हैं तो सामान्य जेनेमरेबल का उपयोग करने का क्या मतलब है? –

+0

यह एक संकलन त्रुटि –

+0

जैसा है: http://stackoverflow.com/questions/6557/in-c-why-cant-a-liststring-object-be-stored-in-a-listobject-variable –

उत्तर

11

इसके लिए तकनीकी शब्द यह है कि जेनेरिक सी # 3.0 और इससे पहले के संस्करण में परिवर्तनीय हैं। सी # 4.0 से आगे, कास्ट काम करता है।

अपरिवर्तनीय क्या मतलब है दो सामान्य प्रकार के बीच कोई रिश्ता नहीं है कि सिर्फ इसलिए कि उनके जेनेरिक प्रकार मापदंडों से संबंधित हैं (अर्थात उप रहे हैं या एक दूसरे के supertypes) है।

आपके उदाहरण में, IEnumerable<object> और IEnumerable<string> के बीच कोई टाइपिंग संबंध नहीं है, सिर्फ इसलिए कि स्ट्रिंग ऑब्जेक्ट का उप-प्रकार है। उन्हें केवल दो पूरी तरह से असंबंधित प्रकार माना जाता है, जैसे स्ट्रिंग और एक इंट (वे अभी भी ऑब्जेक्ट के उपप्रकार हैं, लेकिन सब कुछ है)

इस समस्या के लिए कुछ कामकाज और अपवाद हैं जिन्हें आपने चलाया है।

सबसे पहले, यदि आप .NET 3.0 का उपयोग कर रहे हैं, तो आप प्रत्येक स्ट्रिंग को ऑब्जेक्ट पर अलग-अलग कर सकते हैं, आप Cast<T>() एक्सटेंशन विधि का उपयोग करके ऐसा कर सकते हैं। अन्यथा, आप एक foreach का उपयोग कर सकते हैं और परिणाम को अपने इच्छित स्थिर प्रकार के एक नए चर में डाल सकते हैं।

दूसरा, सरणी संदर्भ प्रकार के लिए एक अपवाद है, यानी एक स्ट्रिंग [] प्रकार में गुजरने वाली विधि [] प्रकार को स्वीकार करने वाली विधि [] प्रकारों को काम करना चाहिए।

+1

बस इस पुराने उत्तर को अद्यतन करें, covariance और contravariance अब सी # में समर्थित हैं, और यह अब एक वैध कलाकार है। –

0

आप

IEnumerable<T> 

का उपयोग करना चाहिए अगर आप विभिन्न प्रकार में पास करना चाहते हैं, तो आप पता लगाने के लिए जो भी लिखते यह है टी क्वेरी कर सकते हैं।

0

इस बारे में सोचने का एक अच्छा तरीका यह है कि "क्या होगा यदि आप ऐसा कर सकें?"। निम्नलिखित उदाहरण लें:

IEnumerable<String> strings=...; 
IEnumerable<Object> objects = strings; // assume this were legal 

objects.Add(new Integer(5)); // what the... 

हमने अभी स्ट्रिंग्स की सूची में एक पूर्णांक जोड़ा है। कंपाइलर टाइप सुरक्षा को संरक्षित करने के लिए करता है।

+0

आईनेमेरेबल में कोई ऐड विधि नहीं है ... और सी # 4.0 में आप वास्तव में इस कलाकार को निष्पादित करने में सक्षम होंगे क्योंकि घोषणा आईन्यूमेरेबल में बदल जाएगी जो इसे (सुरक्षित रूप से) contravariant होने की अनुमति देगी। –

+0

अच्छी तरह से किसी भी जेनेरिक क्लास को प्रतिस्थापित करें जिसमें सूची जैसे –

+0

-1: 'IENumerable ' IENumerable '.NET 4 में बन गया है, विशेष रूप से क्योंकि आपका तर्क एक कंटेनर के लिए समझ में आता है लेकिन * नहीं * गणना के लिए। –

3

IEnumerable<string> पारित करने के लिए IEnumerable<object> की आवश्यकता होती है कार्य करने के लिए सबसे आसान तरीका है इस तरह समारोह परिवर्तित करने के माध्यम से है:

public IEnumerable<object> convert<T>(IEnumerable<T> enumerable) 
    { 
    foreach (T o in enumerable) 
     yield return o; 
    } 

सी # 4 बाहर आता है, यह नहीं आवश्यक है, क्योंकि यह सहप्रसरण और contravariance का समर्थन करेंगे होगा।

+2

यह वही है जो कास्ट <> के लिए है :) –

+0

धन्यवाद! मैंने इस सुझाव को उत्तर में पहले से ही उखाड़ फेंक दिया है। –

8

जैसा कि अन्य ने इंगित किया है, जेनेरिक प्रकार invariant हैं। IEnumerable<T> सह-संस्करण हो सकता है लेकिन सी # वर्तमान में वेरिएंट निर्दिष्ट करने का समर्थन नहीं करता है। सी # 4.0 से वेरिएंट का समर्थन करने की उम्मीद है ताकि भविष्य में इसका समर्थन किया जा सके।

अब इसके आसपास काम करने के लिए आप LINQ एक्सटेंशन विधि Cast<object>() का उपयोग कर सकते हैं। मान लें कि आपके पास Foo नामक एक विधि है जो IEnumerable<object>> लेती है।आप इसे इस तरह से कॉल कर सकते हैं,

Foo(stringEnumerable.Cast<object>()); 
संबंधित मुद्दे