ToList() - Создает ли он новый список?

Скажем, у меня есть класс

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: Прошу прощения, если это кажется очевидным. Но теперь у меня нет компилятора со мной...

Ответ 1

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

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

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

Ответ 2

Из источника Reflector'd:

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

Принятый ответ правильно адресует вопрос OP на основе их примера. Однако это применимо только тогда, когда 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;
}

Несмотря на то, что вышеприведенный код может казаться надуманным, это поведение может выглядеть как тонкая ошибка в других сценариях. См. мой другой пример в ситуации, когда он заставляет задачи неоднократно появляться.

Ответ 7

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

Ответ 8

Просто наткнись на этот старый пост и подумай о добавлении моих двух центов. Как правило, если у меня есть сомнения, я быстро использую метод 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();
    }

И ответьте на мою машину -

  • objs: 45653674
  • objs [0]: 41149443
  • объектов: 45653674
  • объекты [0]: 41149443
  • objectList: 39785641
  • objectList [0]: 41149443
  • whatInt: 5

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

Ответ 9

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

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

Ответ 10

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

Ответ 11

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

Это также обновит исходный объект. Новый список будет содержать ссылки на объекты, содержащиеся в нем, так же как и исходный список. Вы также можете изменить элементы, и обновление будет отражено в другом.

Теперь, если вы обновите список (добавление или удаление элемента), который не будет отображаться в другом списке.

Ответ 12

Я не вижу нигде в документации, что ToList() всегда гарантирует возврат нового списка. Если IEnumerable является списком, может быть более эффективным проверить это и просто вернуть тот же список.

Беспокойство состоит в том, что иногда вы можете быть абсолютно уверены, что возвращенный список будет равен = исходному списку. Поскольку Microsoft не документирует, что ToList вернет новый список, мы не можем быть уверены (если кто-то не нашел эту документацию). Это может также измениться в будущем, даже если оно работает сейчас.

Новый список (IEnumerable enumerablestuff) гарантированно вернет новый список. Я бы использовал это вместо этого.