Search code examples
c#infinite-loopenumerator

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");
}

Solution

  • 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!".