C # में, सूची <string> ऑब्जेक्ट को सूची <ऑब्जेक्ट> चर में संग्रहीत नहीं किया जा सकता


85

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

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

परिणाम में स्पष्ट रूप से प्रकार परिवर्तित नहीं किया जा सकता System.Collections.Generic.List<string>हैSystem.Collections.Generic.List<object>

और तब...

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

परिणाम प्रकार में परिवर्तित नहीं किया जा सकता System.Collections.Generic.List<string>हैSystem.Collections.Generic.List<object>

बेशक, आप इसे स्ट्रिंग सूची से सब कुछ खींचकर और एक समय में एक में वापस डालकर कर सकते हैं, लेकिन यह एक जटिल समाधान है।


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

कम या ज्यादा डुप्लिकेट: stackoverflow.com/questions/317335/…
Gö में जोएल

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

इसका जवाब जॉन स्कीट ने यहां दिया है: stackoverflow.com/a/2033921/1070906
JCH2k

जवाबों:


39

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

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

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

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

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


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

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

@ChrisAmmerman: अगर olइसमें कुछ ऐसा था जो एक तार नहीं है, तो मुझे लगता है कि मैं उम्मीद करूंगा कि कलाकार रनटाइम में विफल होंगे। लेकिन जहां आप वास्तव में परेशानी में पड़ जाते हैं, अगर कास्ट सफल हुआ, और फिर कुछ जोड़ा गया तोol यह एक स्ट्रिंग नहीं है। क्योंकि slएक ही वस्तु को संदर्भित करता है, अब आपके पास List<string>एक गैर-स्ट्रिंग होगी। यह Addसमस्या है, जिसका मुझे अनुमान है कि यह कोड क्यों संकलित नहीं करेगा, लेकिन यदि आप इसे बदलते List<object> olहैं IEnumerable<object> ol, तो यह संकलन करेगा Add। (मैंने इसे C # 4 में चेक किया)
टिम गुडमैन

उस परिवर्तन के साथ, यह संकलित करता है लेकिन फेंकता है InvalidCastExceptionक्योंकि रनटाइम प्रकार olअभी भी है List<object>
टिम गुडमैन

36

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

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

यह बिल्कुल वैसा नहीं है जैसा आपने पूछा है, बल्कि आपको यह करना चाहिए।

संपादित करें: जैसा कि ज़ोबा ने नोट किया है, तब आप सूची प्राप्त करने के लिए ol.ToList () कॉल कर सकते हैं


14

आप विभिन्न प्रकार के मापदंडों के साथ सामान्य प्रकारों के बीच कास्ट नहीं कर सकते। विशिष्ट जेनेरिक प्रकार एक ही वंशानुक्रम के पेड़ का हिस्सा नहीं होते हैं और इसलिए असंबंधित प्रकार होते हैं।

ऐसा करने के लिए प्री-नेट 3.5:

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 का उपयोग करना:

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();

11

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

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

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


6

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

आप इसके बजाय ff कोड आज़माना चाह सकते हैं:

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 will (सैद्धांतिक रूप से) sl की सभी सामग्री को बिना किसी समस्या के कॉपी करता है।





1

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

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


1

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

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

सी # प्रदर्शन आप डाल, कहते हैं, एक से रोकने के लिए जाँच करता है क्रम intमें a


0

यहां किसी भी IList के लिए एक और पूर्व- .NET 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

मेरे पास एक:

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

और मैं इसे भरने के लिए जा रहा था, जो List<object> मेरे लिए काम कर रहा था, वह आखिरकार यही था:

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

.Castयह प्रकार है कि आप एक प्राप्त करना चाहते हैं IEnumerable, उस प्रकार से तो समान किरदार IEnemuerableके लिए 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);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.