Jens
Jens

Reputation: 25583

Changing Properties of IEnumerator<T>.Current

With great surprised I observed the following behavior today: Given a class

class Foo
{
    prop int FooNumber { get; set; }
}

and this code

IEnumerable<Foo> foos = Enumerable.Range(0,3).Select(new Foo());

foreach (var foo in foos)
    foo.Bar = 5;

foreach (var foo in foos)
   Console.Write(foo.Bar);  // Writes 000

while initializing foos to new List<Foo>{ new Foo(), new Foo(), new Foo() } makes the loop write "555".

My question: Why does this happen and is there a way to circumvent this whithout using .ToList() (which needs a comment, since it does not seem to be needed here).

Upvotes: 10

Views: 279

Answers (2)

Jon
Jon

Reputation: 437644

It happens because foos is dynamically produced each time you enumerate it. So during the first iteration you are setting property values on objects that are no longer referenced by anything after the iteration ends. The second iteration works on freshly constructed objects which have the default property value.

Initializing foos to a list of "persistent" objects changes things, as does using .ToList() for the same reason (a "fixed" list is constructed and iterated over twice; the original dynamically produced IEnumerable is only iterated over once).

Having established that you should use .ToList() here: in general I do not feel that it needs a comment because it is not customary to iterate over dynamically produced sequences more than once (I believe many code analysis tools warn against this), but by all means do write one.

Upvotes: 20

to StackOverflow
to StackOverflow

Reputation: 124766

It seems obvious what's happening: each time you enumerate, you're instantiating new Foo objects.

If you want the property values (Foo.Bar) to be preserved, then you're going to have to keep the Foo's somewhere, and ToList() is a simple way of doing this.

Upvotes: 3

Related Questions