2008-08-09 19 views
76

में संग्रहीत क्यों नहीं किया जा सकता है ऐसा लगता है कि एक सूची वस्तु को C# में सूची चर में संग्रहीत नहीं किया जा सकता है, और इसे स्पष्ट रूप से उस तरह से भी नहीं डाला जा सकता है।सी # में, सूची <string> ऑब्जेक्ट को सूची <object> परिवर्तनीय

List<string> sl = new List<string>(); 
List<object> ol; 
ol = sl; 

परिणामों में परोक्ष System.Collections.Generic.List<object>

और फिर करने के लिए प्रकार System.Collections.Generic.List<string> कनवर्ट नहीं कर सकता ...

List<string> sl = new List<string>(); 
List<object> ol; 
ol = (List<object>)sl; 

परिणामों में System.Collections.Generic.List<object>

बेशक करने के लिए प्रकार System.Collections.Generic.List<string> कनवर्ट नहीं कर सकता है, तो आप क्या कर सकते हैं यह सब कुछ स्ट्रिंग सूची से बाहर खींचकर और इसे एक समय में एक में डालकर, लेकिन यह है एक बल्कि ठोस समाधान।

+5

यह सी # 4.0 के साथ बदल जाएगा, तो आप कॉन्वर्सिस और विरोधाभास को देखना चाहते हैं। यह ऐसी चीजों को एक प्रकार से सुरक्षित तरीके से अनुमति देगा। –

+0

अधिक या कम डुप्लिकेट: http://stackoverflow.com/questions/317335/why-can-i-not-return-a-listfoo-if-asked-for-a-listifoo –

+7

जॉन> सी # 4 अनुमति नहीं देगा इस। Ol.Add के बारे में सोचें (नई वस्तु()); – Guillaume

उत्तर

35

इस तरह के बारे में सोचें, अगर आप इस तरह के कलाकार को करना चाहते हैं, और फिर सूची में फू प्रकार का ऑब्जेक्ट जोड़ें, तारों की सूची अब सुसंगत नहीं है। यदि आप पहले संदर्भ को पुन: सक्रिय करना चाहते थे, तो आपको क्लास कास्ट अपवाद मिलेगा क्योंकि एक बार जब आप Foo इंस्टेंस को दबाते हैं, तो Foo को स्ट्रिंग में परिवर्तित नहीं किया जा सका!

एक तरफ ध्यान दें के रूप में, मुझे लगता है कि यह अधिक महत्वपूर्ण है या नहीं, आप रिवर्स डाली कर सकते हैं होगा:

List<object> ol = new List<object>(); 
List<string> sl; 
sl = (List<string>)ol; 

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

क्या कोई जानता है या परीक्षण कर सकता है अगर ऐसी कलाकार सी # में कानूनी है या नहीं?

+4

मुझे लगता है कि आपका उदाहरण एक ही समस्या से पीड़ित है। क्या होता है यदि ओएल में कुछ ऐसा है जो स्ट्रिंग नहीं है? समस्या यह है कि सूची में कुछ तरीके ठीक काम करेंगे, जैसे जोड़ने/डालने। लेकिन पुनरावृत्ति एक असली समस्या हो सकती है। –

+3

एरिक लिपर्ट के पास इस विषय के बारे में ब्लॉग पोस्ट की एक बड़ी श्रृंखला है: यह सामान्य तरीकों से कॉन्वर्सिस और contravariance contraints जोड़ने के लिए क्यों काम कर सकता है, लेकिन कक्षा के स्तर पर हम जिस तरह से काम करना चाहते हैं कभी काम नहीं कर सकते हैं। http://is.gd/3kQc –

+0

@ChrisAmmerman: यदि 'ol' में कुछ ऐसा था जो स्ट्रिंग नहीं है, तो मुझे लगता है कि मैं रनटाइम पर कास्ट विफल होने की अपेक्षा करता हूं। लेकिन जहां आप वास्तव में परेशानी में भाग लेंगे, यदि कलाकार सफल हो गया है, और * * * कुछ 'ओएल' में जोड़ा गया था जो एक स्ट्रिंग नहीं है। चूंकि 'sl' एक ही ऑब्जेक्ट का संदर्भ देता है, अब आपकी 'सूची ' में एक गैर-स्ट्रिंग होगी। 'ऐड' समस्या है, जो मुझे लगता है कि यह कोड संकलित क्यों नहीं करेगा, लेकिन यह संकलित करेगा यदि आप 'सूची ol' को' IENumerable ol' में बदलते हैं, जिसमें 'Add' नहीं है। (मैंने इसे सी # 4 में चेक किया है।) –

12

कारण यह है कि List<> जैसी सामान्य वर्ग सामान्य प्रयोजनों के रूप में बाहरी रूप से इलाज की जाती है। जैसे जब आप List<string>() कहते हैं तो संकलक ListString() (जिसमें तार शामिल हैं) कहते हैं। [तकनीकी लोक: यह एक बेहद सादा-अंग्रेजी-संस्करण संस्करण है जो चल रहा है]

नतीजतन, स्पष्ट रूप से संकलक सूचीकरण को अपने आंतरिक संग्रह की वस्तुओं कास्टिंग करके सूची सूची में कनवर्ट करने के लिए पर्याप्त स्मार्ट नहीं हो सकता है।

यही कारण है कि कनवर्ट() जैसे IENumerable के लिए एक्सटेंशन विधियां हैं जो आपको संग्रह के अंदर संग्रहीत वस्तुओं के लिए आसानी से रूपांतरण की अनुमति देती हैं, जो एक से दूसरे में कास्टिंग के रूप में सरल हो सकती हैं।

3

माइक - मेरा मानना ​​है कि contravariance सी # में अनुमति नहीं है या तो

कुछ अधिक जानकारी के लिए Generic type parameter variance in the CLR देखें।

6

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

इसके बजाय आप एफएफ कोड की कोशिश करना चाहते हो सकता है:

List<string> sl = new List<string>(); 
//populate sl 
List<object> ol = new List<object>(sl); 

या:

List<object> ol = new List<object>(); 
ol.AddRange(sl); 

ol (सैद्धांतिक) समस्याओं के बिना sl के सभी सामग्री की प्रतिलिपि होगा।

35

यदि आप .NET 3.5 का उपयोग कर रहे हैं तो Enumerable.Cast विधि पर एक नज़र डालें। यह एक विस्तार विधि है ताकि आप इसे सीधे सूची में कॉल कर सकें।

List<string> sl = new List<string>(); 
IEnumerable<object> ol; 
ol = sl.Cast<object>(); 

यह बिल्कुल आप के लिए क्या कहा लेकिन चाल करना चाहिए नहीं है।

संपादित करें: Zooba द्वारा बताया गया है, आप तो एक सूची

14

आप विभिन्न प्रकार के मानकों के साथ सामान्य प्रकार के बीच डाली नहीं कर सकते हैं पाने के लिए ol.ToList() कॉल कर सकते हैं। विशिष्ट सामान्य प्रकार एक ही विरासत के पेड़ का हिस्सा नहीं बनते हैं और इसलिए असंबंधित प्रकार हैं।

List<string> sl = new List<string>(); 
// Add strings to sl 

List<object> ol = new List<object>(); 

foreach(string s in sl) 
{ 
    ol.Add((object)s); // The cast is performed implicitly even if omitted 
} 

का उपयोग Linq:

इस पूर्व-नेट 3.5 ऐसा करने के लिए

var sl = new List<string>(); 
// Add strings to sl 

var ol = new List<object>(sl.Cast<object>()); 

// OR 
var ol = sl.Cast<object>().ToList(); 

// OR (note that the cast to object here is required) 
var ol = sl.Select(s => (object)s).ToList(); 
1

वास्तव में ऐसा है कि आप अपने "ol" में किसी भी अजीब "वस्तु" डाल करने के लिए कोशिश मत करो सूची संस्करण (List<object> को अनुमति देने लगते हैं) - क्योंकि आपका कोड तब दुर्घटनाग्रस्त हो जाएगा (क्योंकि सूची वास्तव में List<string> है और केवल स्ट्रिंग प्रकार ऑब्जेक्ट स्वीकार करेगी)। यही कारण है कि आप अपने चर को अधिक सामान्य विनिर्देशन में नहीं डाल सकते हैं।

जावा पर यह दूसरी तरफ है, आपके पास जेनेरिक नहीं है, और इसके बजाय सब कुछ रनटाइम पर ऑब्जेक्ट की सूची है, और आप वास्तव में अपनी अनुमानित रूप से टाइप की गई सूची में किसी भी अजीब वस्तु को सामान दे सकते हैं। "Reified जेनरिक" के लिए खोज जावा की समस्या का एक व्यापक चर्चा को देखने के लिए ...

1
जेनरिक पर

इस तरह के सहप्रसरण समर्थित नहीं है, लेकिन आप वास्तव में सरणियों के साथ ऐसा कर सकते हैं:

object[] a = new string[] {"spam", "eggs"}; 

सी # करने के लिए क्रम जाँचों का निष्पादन आपको inta में डालने, कहने से रोकें।

5

हाँ, आप कर सकते हैं, .NET 3.5 से:

List<string> sl = new List<string>(); 
List<object> ol = sl.Cast<object>().ToList(); 
0

यहां किसी भी आईएलआईस्ट के लिए एक और प्री-नेट 3.5 समाधान है जिसकी सामग्री को पूरी तरह से डाला जा सकता है।

public IList<B> ConvertIList<D, B>(IList<D> list) where D : B 
{ 
    List<B> newList = new List<B>(); 

    foreach (D item in list) 
    { 
     newList.Add(item); 
    } 

    return newList; 
} 

मैं एक है

0

(Zooba के उदाहरण के आधार पर):

private List<Leerling> Leerlingen = new List<Leerling>(); 

और मैं एक List<object> क्या अंत में मेरे लिए काम किया में एकत्र किए गए आंकड़ों के साथ इसे भरने जा रहा था इस एक था :

Leerlingen = (List<Leerling>)_DeserialiseerLeerlingen._TeSerialiserenObjecten.Cast<Leerling>(); 

.Cast इसे टाइप करने के लिए और आप उस प्रकार से IEnumerable प्राप्त करना चाहते हैं, फिर को List<> पर टाइप करें।

0

एमएम, पिछली टिप्पणियों के लिए धन्यवाद मुझे इसे खोजने के दो तरीके मिले। पहले एक IEnumerable वस्तु सूची में कास्टिंग तत्वों की स्ट्रिंग सूची हो रही है और उसके बाद:

IEnumerable<object> ob; 
List<string> st = new List<string>(); 
ob = st.Cast<object>(); 

और दूसरा एक IEnumerable ऑब्जेक्ट प्रकार से परहेज है, बस स्ट्रिंग कास्टिंग प्रकार आपत्ति उठाने का और उसके बाद समारोह का उपयोग कर " toList() "एक ही वाक्य में:

List<string> st = new List<string>(); 
List<object> ob = st.Cast<object>().ToList(); 

मुझे दूसरा तरीका पसंद है। आशा है कि ये आपकी मदद करेगा।

0
List<string> sl = new List<string>(); 
List<object> ol; 
ol = new List<object>(sl); 
संबंधित मुद्दे