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;

}

কেন?

পি / এস: এটি সন্ধান করা সুস্পষ্ট বলে মনে হলে আমি দুঃখিত। তবে আমার এখন আমার সাথে সংকলক নেই ...


এটা phrasing এর ওয়ান ওয়ে, যে হয় .ToList()একটি তোলে অগভীর কপি। তথ্যসূত্রগুলি অনুলিপি করা হয়েছে, তবে নতুন উল্লেখগুলি এখনও একই সূত্রগুলিতে নির্দেশ করে যা মূল উল্লেখগুলি উল্লেখ করে। আপনি যখন এটি ভাবেন তখন কোনও প্রকারের মতো ToListতৈরি করতে পারবেন না । new MyObject()MyObjectclass
জেপ্পে স্টিগ নীলসন

উত্তর:


217

হ্যাঁ, ToListএকটি নতুন তালিকা তৈরি করবে, তবে যেহেতু এই ক্ষেত্রে MyObjectএকটি রেফারেন্স টাইপ হয় তবে নতুন তালিকায় মূল তালিকা হিসাবে একই জিনিসগুলির রেফারেন্স থাকবে।

SimpleIntনতুন তালিকায় রেফারেন্সযুক্ত কোনও সামগ্রীর সম্পত্তি আপডেট করাও মূল তালিকার সমতুল্য বস্তুকে প্রভাবিত করবে।

(যদি MyObjectএটির structপরিবর্তে ঘোষিত হয় classতবে নতুন তালিকায় মূল তালিকার উপাদানগুলির অনুলিপি থাকবে এবং নতুন তালিকার কোনও উপাদানের সম্পত্তি আপডেট করা মূল তালিকার সমতুল্য উপাদানকে প্রভাবিত করবে না ))


1
এছাড়াও লক্ষ করুন যে কোনও Listস্ট্রাক্টের সাথে একটি অ্যাসাইনমেন্টের objectList[0].SimpleInt=5অনুমতি দেওয়া হবে না (সি # কম্পাইল-টাইম ত্রুটি)। কারণ সূচকের সূচকের getঅ্যাক্সেসরের রিটার্ন মান কোনও পরিবর্তনশীল নয় (এটি কোনও স্ট্রাক্ট মূল্যের প্রত্যাবর্তিত অনুলিপি), এবং সুতরাং তার অ্যাসাইনমেন্ট এক্সপ্রেশন সহ এর সদস্যকে সেট করার.SimpleInt অনুমতি দেওয়া হয় না (এটি কোনও অনুলিপি পরিবর্তন করে রাখে না) । ঠিক আছে, কে যাইহোক পরিবর্তিত কৌশলগুলি ব্যবহার করে?
জেপ্পে স্টিগ নীলসেন

2
@ জেপ্পে স্টিগ নিলসন: হ্যাঁ। এবং, একইভাবে, সংকলক এছাড়াও আপনার পছন্দ মতো স্টাফ করা বন্ধ করবে foreach (var s in listOfStructs) { s.SimpleInt = 42; }সত্যিই কদর্য gotcha হয় যখন আপনি কিছু প্রচেষ্টা 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);
}

হ্যাঁ, আপনার মূল তালিকাটি আপডেট করা হবে না (যেমন সংযোজন বা অপসারণ) তবে রেফারেন্সযুক্ত বস্তুগুলি তা করবে will


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

হ্যাঁ, এটি একটি নতুন তালিকা তৈরি করে। এটি নকশা দ্বারা।

তালিকায় মূল গণনাক্রমের মতো একই ফলাফল থাকবে তবে ধ্রুবক (মেমরির) সংগ্রহে পরিণত হয়েছে। এটি আপনাকে ক্রমটি পুনর্নির্মাণ ব্যয় না করে একাধিকবার ফলাফল গ্রাস করতে দেয়।

লিনকিউ সিকোয়েন্সগুলির সৌন্দর্য হ'ল তারা কম্পোজেবল। প্রায়শই, 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();
    }

এবং আমার মেশিনে উত্তর -

  • আপত্তি: 45653674
  • আপত্তি [0]: 41149443
  • অবজেক্টস: 45653674
  • অবজেক্টস [0]: 41149443
  • অবজেক্টলিস্ট: 39785641
  • অবজেক্টলিস্ট [0]: 41149443
  • কি আছে: 5

সুতরাং মূলত যে জিনিসটি তালিকা বহন করে তা উপরের কোডে একই থাকে the আশা করি এই পদ্ধতির সাহায্য করবে।


4

আমি মনে করি যে এটিলিস্ট একটি গভীর বা অগভীর অনুলিপি করে কিনা তা জিজ্ঞাসার সমতুল্য। যেহেতু টোললিস্টে মাইবজেক্টের ক্লোন করার কোনও উপায় নেই, এটি অবশ্যই অগভীর অনুলিপি করবে, সুতরাং তৈরি তালিকায় মূলটির মতো একই রেফারেন্স রয়েছে, তাই কোডটি 5 ফেরত দেয়।


2

ToList একেবারে নতুন তালিকা তৈরি করবে।

তালিকার আইটেমগুলি যদি মান ধরণের হয় তবে এগুলি সরাসরি আপডেট করা হবে, যদি তারা রেফারেন্স ধরণের হয় তবে রেফারেন্সযুক্ত বস্তুগুলিতে কোনও পরিবর্তনই প্রতিফলিত হবে।


2

যে ক্ষেত্রে উত্স অবজেক্টটি সত্যিকারের আইনুনামেবল (যেমন কেবল একটি সংগ্রহকে একটি গণ্যযোগ্য হিসাবে প্যাকেজ করা নয়), টোললিস্ট () মূল আইমনামেবলের মতো একই অবজেক্টের রেফারেন্সগুলি ফিরিয়ে দিতে পারে না। এটি বস্তুর একটি নতুন তালিকা ফিরিয়ে দেবে, কিন্তু সেই জিনিসগুলি আবার নতুন করে গণনা করা হলে আইনামিউরেবলের দ্বারা উত্পন্ন বস্তুর সমান বা সমানও নাও হতে পারে


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

এটি আসল বস্তুটিও আপডেট করবে। নতুন তালিকায় মূল তালিকার মতো এটির মধ্যে থাকা অবজেক্টের রেফারেন্স থাকবে। আপনি উপাদানগুলি পরিবর্তন করতে পারেন এবং আপডেটটি অন্যটিতে প্রতিফলিত হবে।

এখন আপনি যদি একটি তালিকা আপডেট করেন (কোনও আইটেম যুক্ত বা মুছুন) যা অন্য তালিকায় প্রতিফলিত হবে না।


1

ডকুমেন্টেশনে আমি কোথাও দেখতে পাচ্ছি না যে টোললিস্ট () সর্বদা একটি নতুন তালিকা ফিরিয়ে দেওয়ার গ্যারান্টিযুক্ত। যদি একটি IEnumerable একটি তালিকা হয়, এটি এটি পরীক্ষা করে কেবল একই তালিকাটি ফিরিয়ে দেওয়া আরও কার্যকর হতে পারে।

উদ্বেগটি হ'ল কখনও কখনও আপনি নিখুঁতভাবে নিশ্চিত হতে চাইতে পারেন যে প্রত্যাবর্তিত তালিকাটি মূল তালিকাটিতে! = যেহেতু মাইক্রোসফ্ট ডকুমেন্ট করে না যে টোললিস্ট একটি নতুন তালিকা ফিরিয়ে দেবে, আমরা নিশ্চিত হতে পারি না (যদি না কেউ সেই ডকুমেন্টেশন না পেয়ে থাকে)। এটি যদি এখন কাজ করে তবে ভবিষ্যতে এটি পরিবর্তনও করতে পারে।

নতুন তালিকা (IEnumerable enumerablestuff) একটি নতুন তালিকা ফেরত দেওয়ার গ্যারান্টিযুক্ত। আমি পরিবর্তে এটি ব্যবহার করতে হবে।



1
@ রেমন্ডচেন এটি আইনামেবারেবলের পক্ষে সত্য, তবে তালিকার জন্য নয় for যদিও ToListএটিকে ডেকে একটি নতুন তালিকা অবজেক্ট রেফারেন্স তৈরি করা হয়েছে বলে মনে হচ্ছে List, বেনবি ঠিক তখনই বলেছেন যখন এটি এমএস ডকুমেন্টেশনের দ্বারা নিশ্চিত নয়।
তেজয়

@ রেইমন্ডচেন ক্রিসএস উত্স অনুসারে IEnumerable<>.ToList()বাস্তবে বাস্তবায়িত হয়েছে new List<>(source)এবং এর জন্য কোনও নির্দিষ্ট ওভাররাইড নেই List<>, সুতরাং List<>.ToList()প্রকৃতপক্ষে একটি নতুন তালিকা অবজেক্ট রেফারেন্স ফিরে আসে। তবে আবারও, এমএস ডকুমেন্টেশন অনুসারে, ভবিষ্যতে এটির কোনও পরিবর্তন না হওয়ার কোনও গ্যারান্টি নেই, যদিও এটি সম্ভবত বেশিরভাগ কোডটি ভেঙে ফেলবে।
তেজয়
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.