ToList () - создает ли он новый список? - PullRequest
161 голосов
/ 05 мая 2010

Допустим, у меня есть класс

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;

}

Почему?

P / S: Извините, если кажется очевидным выяснить. Но сейчас у меня нет компилятора ...

Ответы [ 12 ]

197 голосов
/ 05 мая 2010

Да, ToList создаст новый список, но поскольку в этом случае MyObject является ссылочным типом, тогда новый список будет содержать ссылки на те же объекты, что и исходный список.

Обновление свойства SimpleInt объекта, на который есть ссылка в новом списке, также повлияет на эквивалентный объект в исходном списке.

(Если MyObject было объявлено как struct, а не class, тогда новый список будет содержать копии элементов в исходном списке, а обновление свойства элемента в новом списке не влияет на эквивалентный элемент в исходном списке.)

58 голосов
/ 05 мая 2010

Из источника Отражателя:

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

Так что да, ваш первоначальный список не будет обновляться (то есть, добавления или удаления), однако ссылочные объекты будут.

30 голосов
/ 05 мая 2010

ToList всегда будет создавать новый список, который не будет отражать никаких последующих изменений в коллекции.

Тем не менее, он будет отражать изменения в самих объектах (если они не изменяемые структуры).

Другими словами, если вы замените объект в исходном списке другим объектом, ToList все равно будет содержать первый объект.
Однако, если вы измените один из объектов в исходном списке, ToList все равно будет содержать тот же (измененный) объект.

11 голосов
/ 12 июня 2014

Принятый ответ правильно отвечает на вопрос ОП на основании его примера. Тем не менее, он применяется только тогда, когда ToList применяется к бетонному сбору; он не сохраняется, когда элементы исходной последовательности еще не созданы (из-за отложенного выполнения). В последнем случае вы можете получать новый набор предметов каждый раз, когда вы звоните ToList (или перечисляете последовательность).

Вот адаптация кода OP, чтобы продемонстрировать это поведение:

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 голосов
/ 05 мая 2010

Да, он создает новый список. Это по замыслу.

Список будет содержать те же результаты, что и исходная перечисляемая последовательность, , но материализуется в постоянную (в памяти) коллекцию. Это позволяет использовать результаты несколько раз без затрат на повторный расчет последовательности.

Прелесть последовательностей LINQ в том, что они компонуются. Часто получаемый IEnumerable<T> является результатом объединения нескольких операций фильтрации, упорядочения и / или проецирования. Методы расширения, такие как ToList() и ToArray(), позволяют преобразовывать вычисленную последовательность в стандартную коллекцию.

6 голосов
/ 05 мая 2010

Создается новый список, но элементы в нем являются ссылками на оригинальные элементы (как и в оригинальном списке). Изменения в самом списке независимы, но элементы найдут изменения в обоих списках.

5 голосов
/ 28 августа 2014

Просто наткнулся на этот старый пост и подумал добавить мои два цента. Обычно, если у меня есть сомнения, я быстро использую метод GetHashCode () для любого объекта для проверки идентичности. Так что выше -

    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
  • objs [0]: 41149443
  • объекты: 45653674
  • объекты [0]: 41149443
  • objectList: 39785641
  • objectList [0]: 41149443
  • Что: 5

Так что, по сути, объект, который несет список, остается таким же в приведенном выше коде. Надеюсь, что подход поможет.

4 голосов
/ 05 мая 2010

Я думаю, что это равносильно тому, чтобы спросить, делает ли ToList глубокую или поверхностную копию. Поскольку ToList не имеет возможности клонировать MyObject, он должен делать поверхностную копию, поэтому созданный список содержит те же ссылки, что и исходный, поэтому код возвращает 5.

2 голосов
/ 26 августа 2013

В случае, когда исходный объект является истинным IEnumerable (то есть не просто коллекцией, упакованной как перечисляемая), ToList () НЕ может возвращать те же ссылки на объекты, что и в исходном IEnumerable. Он вернет новый список объектов, но эти объекты могут не совпадать или даже не совпадать с объектами, полученными от IEnumerable при его повторном перечислении

2 голосов
/ 05 мая 2010

ToList создаст новый список.

Если элементы в списке являются типами значений, они будут непосредственно обновлены, если они являются ссылочными типами, любые изменения будут отражены обратно в ссылочных объектах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...