In C#, I have noticed that if I am running a foreach loop on a LINQ generated IEnumerable
collection and try to modify the contents of each T element,
You are right, it is deferred execution. A new MyClass instance is created each time you iterate the IEnumerable. By calling ToList or ToArray you then create a List or Array and populate it with the new MyClass instances created from the iteration of the IEnumerable.
Deferred execution is the indeed the key point.
Executing myClassEnumerable.First().Str
will reexecute your query ints.Select(i => new MyClass(i));
and so it will give you a new IEnumerable with a new list of integers.
You can see this in action using your debugger. Put a breakpoint at the new MyClass(i)
part of the IEnumerable select and you will see that this part get's hit again when you execute it for Console.WriteLine