ToList () - क्या यह एक नई सूची बनाता है?


176

मान लीजिए कि मेरे पास एक क्लास है

public class MyObject
{
   public int SimpleInt{get;set;}
}

और मेरे पास एक है List<MyObject>, और मैं ToList()इसे और फिर उनमें से एक को SimpleIntबदल देता हूं, क्या मेरे परिवर्तन को मूल सूची में वापस प्रचारित किया जाएगा। दूसरे शब्दों में, निम्नलिखित विधि का आउटपुट क्या होगा?

public void RunChangeList()
{
  var objs = new List<MyObject>(){new MyObject(){SimpleInt=0}};
  var whatInt = ChangeToList(objs );
}
public int ChangeToList(List<MyObject> objects)
{
  var objectList = objects.ToList();
  objectList[0].SimpleInt=5;
  return objects[0].SimpleInt;

}

क्यों?

पी / एस: मुझे खेद है अगर यह पता लगाना स्पष्ट लगता है। लेकिन अब मेरे साथ कंपाइलर नहीं है ...


इसका एक तरीका यह है कि उथली प्रतिलिपि .ToList()बनाता है । संदर्भों की नकल की जाती है, लेकिन नए संदर्भ अभी भी उन्हीं उदाहरणों की ओर इशारा करते हैं जैसे मूल संदर्भ इंगित करते हैं। जब आप इसके बारे में सोचते हैं, किसी भी नहीं बना सकते जब एक है प्रकार। ToListnew MyObject()MyObjectclass
जेपी स्टिग नील्सन

जवाबों:


217

हां, ToListएक नई सूची बनाएगा, लेकिन क्योंकि इस मामले MyObjectमें एक संदर्भ प्रकार है तो नई सूची में मूल सूची के समान वस्तुओं के संदर्भ होंगे।

SimpleIntनई सूची में संदर्भित किसी वस्तु की संपत्ति को अद्यतन करने से मूल सूची में समतुल्य वस्तु भी प्रभावित होगी।

(यदि MyObjectइसके structबजाय एक classनई सूची में घोषित किया गया था, तो मूल सूची में तत्वों की प्रतियां शामिल होंगी, और नई सूची में किसी तत्व की संपत्ति को अपडेट करने से मूल सूची में समतुल्य तत्व प्रभावित नहीं होगा ।)


1
यह भी ध्यान दें कि Listकई संरचनाओं के साथ, असाइनमेंट की तरह objectList[0].SimpleInt=5अनुमति नहीं दी जाएगी (C # संकलन-समय त्रुटि)। ऐसा इसलिए है क्योंकि सूची अनुक्रमणिका के एक्सेसर का रिटर्न वैल्यू getएक वैरिएबल नहीं है (यह किसी स्ट्रक्चर वैल्यू की लौटी हुई कॉपी है), और इसलिए असाइनमेंट एक्सप्रेशन के साथ इसके मेंबर को सेट करने.SimpleInt की अनुमति नहीं है (यह उस कॉपी को म्यूट कर देगा जिसे नहीं रखा गया है) । खैर, वैसे भी जो परिवर्तनशील संरचनाओं का उपयोग करता है?
जेपी स्टिग नील्सन

2
@ जेपी स्टिग नील्सन: हाँ। और, इसी तरह, संकलक भी आपकी तरह सामान करना बंद कर देगा foreach (var s in listOfStructs) { s.SimpleInt = 42; }वास्तव में बुरा पकड़ लिया जैसे कि जब आप कुछ प्रयास है listOfStructs.ForEach(s => s.SimpleInt = 42)संकलक यह और अपवाद के बिना कोड रन की अनुमति देता है, लेकिन सूची में structs नहीं बदलेगी:
ल्यूक जुएल

62

प्रतिक्षेपक स्रोत से:

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    return new List<TSource>(source);
}

तो हां, आपकी मूल सूची अपडेट नहीं की जाएगी (यानी अतिरिक्त या निष्कासन) हालांकि संदर्भित ऑब्जेक्ट होंगे।


32

ToList हमेशा एक नई सूची बनाएगा, जो संग्रह के बाद के परिवर्तनों को प्रतिबिंबित नहीं करेगा।

हालाँकि, यह स्वयं वस्तुओं में परिवर्तन को प्रतिबिंबित करेगा (जब तक कि वे परस्पर परिवर्तनशील न हों)।

दूसरे शब्दों में, यदि आप मूल सूची में किसी ऑब्जेक्ट को एक अलग ऑब्जेक्ट के साथ बदलते हैं, तो ToListभी पहले ऑब्जेक्ट शामिल होगा।
हालाँकि, यदि आप मूल सूची ToListमें से किसी एक वस्तु को संशोधित करते हैं , तो भी उसमें वही (संशोधित) वस्तु होगी।


12

स्वीकृत उत्तर सही ढंग से अपने उदाहरण के आधार पर ओपी के प्रश्न को संबोधित करता है। हालांकि, यह केवल तब लागू होता है जब ToListएक ठोस संग्रह पर लागू किया जाता है; यह तब नहीं होता जब स्रोत अनुक्रम के तत्वों को अभी तक त्वरित किया जाना है (आस्थगित निष्पादन के कारण)। उत्तरार्द्ध के मामले में, आपको हर बार आपके द्वारा कॉल किए जाने वाले आइटम का एक नया सेट मिल सकता है ToList(या अनुक्रम को गणना करना)।

इस व्यवहार को प्रदर्शित करने के लिए ओपी कोड का एक अनुकूलन है:

public static void RunChangeList()
{
    var objs = Enumerable.Range(0, 10).Select(_ => new MyObject() { SimpleInt = 0 });
    var whatInt = ChangeToList(objs);   // whatInt gets 0
}

public static int ChangeToList(IEnumerable<MyObject> objects)
{
    var objectList = objects.ToList();
    objectList.First().SimpleInt = 5;
    return objects.First().SimpleInt;
}

जब भी उपरोक्त कोड को चोट लग सकती है, यह व्यवहार अन्य परिदृश्यों में एक सूक्ष्म बग के रूप में दिखाई दे सकता है। ऐसी स्थिति के लिए मेरे अन्य उदाहरण देखें जहां यह कार्यों को बार-बार पैदा करने का कारण बनता है।


11

हां, यह एक नई सूची बनाता है। यह डिजाइन द्वारा है।

सूची में मूल गणना अनुक्रम के समान परिणाम शामिल होंगे, लेकिन एक स्थिर (इन-मेमोरी) संग्रह में भौतिक। यह आपको अनुक्रम को फिर से क्रमित करने की लागत को प्रभावित किए बिना कई बार परिणामों का उपभोग करने की अनुमति देता है।

LINQ दृश्यों की सुंदरता यह है कि वे रचना योग्य हैं। अक्सर, IEnumerable<T>आपको मिलता है कई फ़िल्टरिंग, ऑर्डरिंग और / या प्रोजेक्शन ऑपरेशंस के संयोजन का परिणाम है। एक्सटेंशन के तरीके ToList()और ToArray()गणना क्रम को मानक संग्रह में बदलने की अनुमति देता है।


6

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


6

बस इस पुरानी पोस्ट पर ठोकर खाई और मेरे दो सेंट जोड़ने का सोचा। आम तौर पर, अगर मुझे संदेह है, तो मैं पहचानों की जांच करने के लिए किसी भी वस्तु पर जल्दी से गेटहैशकोड () पद्धति का उपयोग करता हूं। तो ऊपर के लिए -

    public class MyObject
{
    public int SimpleInt { get; set; }
}


class Program
{

    public static void RunChangeList()
    {
        var objs = new List<MyObject>() { new MyObject() { SimpleInt = 0 } };
        Console.WriteLine("objs: {0}", objs.GetHashCode());
        Console.WriteLine("objs[0]: {0}", objs[0].GetHashCode());
        var whatInt = ChangeToList(objs);
        Console.WriteLine("whatInt: {0}", whatInt.GetHashCode());
    }

    public static int ChangeToList(List<MyObject> objects)
    {
        Console.WriteLine("objects: {0}", objects.GetHashCode());
        Console.WriteLine("objects[0]: {0}", objects[0].GetHashCode());
        var objectList = objects.ToList();
        Console.WriteLine("objectList: {0}", objectList.GetHashCode());
        Console.WriteLine("objectList[0]: {0}", objectList[0].GetHashCode());
        objectList[0].SimpleInt = 5;
        return objects[0].SimpleInt;

    }

    private static void Main(string[] args)
    {
        RunChangeList();
        Console.ReadLine();
    }

और मेरी मशीन पर जवाब दें -

  • objs: 45653674
  • objs [0]: 41149443
  • ऑब्जेक्ट्स: 45653674
  • ऑब्जेक्ट्स [0]: 41149443
  • ऑब्जेक्टलिस्ट: 39785641
  • ऑब्जेक्टलिस्ट [0]: 41149443
  • whatInt: 5

तो अनिवार्य रूप से वह वस्तु जो सूची वहन करती है, उपरोक्त कोड में समान रहती है। आशा है कि दृष्टिकोण मदद करता है।


4

मुझे लगता है कि यह पूछने के बराबर है कि क्या टोलिस्ट गहरी या उथली नकल करता है। चूंकि टॉलिस्ट के पास MyObject को क्लोन करने का कोई तरीका नहीं है, इसलिए इसे एक उथली प्रतिलिपि करना होगा, इसलिए बनाई गई सूची में मूल एक के समान संदर्भ होते हैं, इसलिए कोड 5 वापस आ जाता है।


2

ToList एक नई सूची बनाएगा।

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


2

उस स्थिति में जहां स्रोत ऑब्जेक्ट एक सत्य IEnumerable है (यानी केवल संग्रहणीय रूप में पैक नहीं किया गया है), ToList () मूल IEnumerable के रूप में एक ही ऑब्जेक्ट संदर्भ वापस नहीं कर सकता है। यह वस्तुओं की एक नई सूची लौटाएगा, लेकिन उन वस्तुओं को समान या यहां तक ​​कि समान नहीं हो सकता है जो IEnumerable द्वारा उत्पादित वस्तुओं के बराबर है जब इसे फिर से एन्यूमरेट किया जाता है


1
 var objectList = objects.ToList();
  objectList[0].SimpleInt=5;

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

अब यदि आप किसी सूची को अपडेट करते हैं (किसी आइटम को जोड़ना या हटाना) जो दूसरी सूची में परिलक्षित नहीं होगी।


1

मैं दस्तावेज में कहीं भी नहीं देखता कि टोलिस्ट () को हमेशा एक नई सूची वापस करने की गारंटी दी जाती है। यदि कोई IEnumerable एक सूची है, तो इसके लिए जाँच करने के लिए अधिक कुशल हो सकता है और बस उसी सूची को वापस कर सकता है।

चिंता यह है कि कभी-कभी आप पूरी तरह से सुनिश्चित होना चाहते हैं कि लौटी सूची मूल सूची के लिए! = है। क्योंकि Microsoft यह दावा नहीं करता है कि ToList एक नई सूची लौटाएगा, हम निश्चित नहीं हो सकते (जब तक कि कोई उस दस्तावेज़ को नहीं मिला)। यह भविष्य में भी बदल सकता है, भले ही यह अब काम करता हो।

नई सूची (IEnumerable enumerablestuff) एक नई सूची वापस करने की गारंटी है। मैं इसके बजाय इसका इस्तेमाल करूंगा।


2
इसे यहाँ प्रलेखन में कहा गया है: " ToList <TSource> (IEnumerable <TSource>) विधि तत्काल क्वेरी मूल्यांकन को बाध्य करती है और एक सूची <T> देता है जिसमें क्वेरी परिणाम होते हैं। आप इस विधि को अपनी क्वेरी में संलग्न कर सकते हैं। क्वेरी परिणामों की एक कैश्ड प्रतिलिपि। "दूसरा वाक्य दोहराता है कि क्वेरी के मूल्यांकन के बाद मूल सूची में कोई भी परिवर्तन लौटे सूची पर कोई प्रभाव नहीं है।
रेमंड चेन

1
@RaymondChen यह IEnumerables के लिए सही है, लेकिन सूचियों के लिए नहीं। हालाँकि , ToListजब कहा जाता है तो एक नई सूची ऑब्जेक्ट संदर्भ बनाता है List, बेनबी सही है जब वह कहता है कि यह एमएस प्रलेखन द्वारा गारंटी नहीं है।
तीजय

@RaymondChen क्रिस स्रोत के अनुसार, IEnumerable<>.ToList()वास्तव में के रूप में लागू किया गया है new List<>(source)और इसके लिए कोई विशिष्ट ओवरराइड नहीं है List<>, इसलिए List<>.ToList()वास्तव में एक नई सूची ऑब्जेक्ट संदर्भ वापस करता है। लेकिन एक बार फिर, एमएस प्रलेखन के अनुसार, भविष्य में इसे नहीं बदलने की कोई गारंटी नहीं है, हालांकि यह संभवतः वहां के अधिकांश कोड को तोड़ देगा।
तीज ०
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.