ToList()-- does it create a new list?
Solution 1:
Yes, ToList
will create a new list, but because in this case MyObject
is a reference type then the new list will contain references to the same objects as the original list.
Updating the SimpleInt
property of an object referenced in the new list will also affect the equivalent object in the original list.
(If MyObject
was declared as a struct
rather than a class
then the new list would contain copies of the elements in the original list, and updating a property of an element in the new list would not affect the equivalent element in the original list.)
Solution 2:
From the Reflector'd source:
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return new List<TSource>(source);
}
So yes, your original list won't be updated (i.e. additions or removals) however the referenced objects will.
Solution 3:
ToList
will always create a new list, which will not reflect any subsequent changes to the collection.
However, it will reflect changes to the objects themselves (Unless they're mutable structs).
In other words, if you replace an object in the original list with a different object, the ToList
will still contain the first object.
However, if you modify one of the objects in the original list, the ToList
will still contain the same (modified) object.
Solution 4:
The accepted answer correctly addresses the OP's question based on his example. However, it only applies when ToList
is applied to a concrete collection; it does not hold when the elements of the source sequence have yet to be instantiated (due to deferred execution). In case of the latter, you might get a new set of items each time you call ToList
(or enumerate the sequence).
Here is an adaptation of the OP's code to demonstrate this behaviour:
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;
}
Whilst the above code may appear contrived, this behaviour can appear as a subtle bug in other scenarios. See my other example for a situation where it causes tasks to get spawned repeatedly.
Solution 5:
Yes, it creates a new list. This is by design.
The list will contain the same results as the original enumerable sequence, but materialized into a persistent (in-memory) collection. This allows you to consume the results multiple times without incurring the cost of recomputing the sequence.
The beauty of LINQ sequences is that they are composable. Often, the IEnumerable<T>
you get is the result of combining multiple filtering, ordering, and/or projection operations. Extension methods like ToList()
and ToArray()
allow you to convert the computed sequence into a standard collection.