Strange behavior of Enumerator.MoveNext()

Could someone explain why this code is running in infinity loop? Why MoveNext() return true always?

var x = new { TempList = new List<int> { 1, 3, 6, 9 }.GetEnumerator() };
while (x.TempList.MoveNext())
{
  Console.WriteLine("Hello World");
}
Jon Skeet
people
quotationmark

List<T>.GetEnumerator() returns a mutable value type (List<T>.Enumerator). You're storing that value in the anonymous type.

Now, let's have a look at what this does:

while (x.TempList.MoveNext())
{
    // Ignore this
}

That's equivalent to:

while (true)
{
    var tmp = x.TempList;
    var result = tmp.MoveNext();
    if (!result)
    {
        break;
    }

    // Original loop body
}

Now note what we're calling MoveNext() on - the copy of the value which is in the anonymous type. You can't actually change the value in the anonymous type - all you've got is a property you can call, which will give you a copy of the value.

If you change the code to:

var x = new { TempList = (IEnumerable<int>) new List<int> { 1, 3, 6, 9 }.GetEnumerator() };

... then you'll end up getting a reference in the anonymous type. A reference to a box containing the mutable value. When you call MoveNext() on that reference, the value inside the box will be mutated, so it'll do what you want.

For analysis on a very similar situation (again using List<T>.GetEnumerator()) see my 2010 blog post "Iterate, damn you!".

people

See more on this question at Stackoverflow