Скажем, у меня есть класс
public class MyObject
{
public int SimpleInt{get;set;}
}
И у меня есть a 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: я сожалею, если кажется очевидным узнать. Но у меня нет компилятора со мной теперь...
Да, ToList
создаст новый список, но поскольку в данном случае MyObject
является ссылочным типом, то новый список будет содержать ссылки на те же объекты, что и исходный список.
Обновление свойства SimpleInt
объекта, на который есть ссылка в новом списке, также повлияет на эквивалентный объект в исходном списке.
(Если MyObject
был объявлен как struct
, а не как class
, то новый список будет содержать копии элементов исходного списка, и обновление свойства элемента в новом списке не повлияет на эквивалентный элемент в исходном списке)
Из источника Reflector'd:
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return new List<TSource>(source);
}
Итак, да, ваш исходный список не будет обновляться (т.е. добавляться или удаляться), но объекты, на которые есть ссылки, будут обновляться.
ToList
всегда будет создавать новый список, который не будет отражать никакие последующие изменения в коллекции.
Однако он будет отражать изменения самих объектов (если только они не изменяемые структуры).
Другими словами, если вы замените объект в исходном списке другим объектом, ToList
по-прежнему будет содержать первый объект.
Однако, если вы измените один из объектов в исходном списке, ToList
все равно будет содержать тот же (измененный) объект.
Да, он создает новый список. Так и задумано.
Список будет содержать те же результаты, что и исходная перечислимая последовательность, но материализованные в постоянную (в памяти) коллекцию. Это позволяет вам использовать результаты многократно без затрат на повторное вычисление последовательности.
Красота последовательностей LINQ заключается в том, что они являются композиционными. Часто IEnumerable
, который вы получаете, является результатом объединения нескольких операций фильтрации, упорядочивания и/или проецирования. Такие методы расширения, как ToList()
и ToArray()
, позволяют преобразовать вычисленную последовательность в стандартную коллекцию.
Я думаю, что это эквивалентно вопросу, выполняет ли ToList глубокую или неглубокую копию. Поскольку ToList не имеет возможности клонировать MyObject, он должен делать неглубокую копию, поэтому созданный список содержит те же ссылки, что и исходный, поэтому код возвращает 5.
Создается новый список, но элементы в нем являются ссылками на исходные элементы (как и в исходном списке). Изменения в самом списке независимы, но изменения в элементах будут найдены в обоих списках.
ToList
создаст совершенно новый список.
Если элементы в списке являются типами значений, они будут обновлены напрямую, если они являются ссылочными типами, любые изменения будут отражены обратно в ссылающихся объектах.
var objectList = objects.ToList();
objectList[0].SimpleInt=5;
Это обновит и исходный объект. Новый список будет содержать ссылки на содержащиеся в нем объекты, как и исходный список. Вы можете изменить элементы любого из них, и обновление будет отражено в другом.
Теперь, если вы обновите список (добавив или удалив элемент), это не будет отражено в другом списке.