0

Although the iterator variable in a foreach loop is immutable, I am able to modify my collection in the example below if I use Where() to do the modification:

    static void Main(string[] args)
    {
        var list = new List<int> { 1, 2, 3, 4 };

        foreach (var listElement in list)
        {
            Console.WriteLine(listElement + " ");
            list = list.Where(x => x != listElement).ToList();
        }

        Console.WriteLine("Count: " + list.Count);
    }

Output:

1
2
3
4
Count: 0

Could someone please explain this behavior?

pmohandas
  • 3,669
  • 2
  • 23
  • 25

4 Answers4

2

I believe that in the foreach (var listElement in list) you are getting the enumerator for the reference of list at that point in time.

In your loop you assign a new instance to the list variable, but the enumerator the loop is using keeps the reference to the original enumerator.

What you can not do is mutate the original instance. i.e. perform list.Remove(listElement) as this would be mutating the actual data you are trying to enumerate

It might help if the code is expanded to what the foreach loop is actually doing

static void Main(string[] args)
{
    var list = new List<int> { 1, 2, 3, 4 };
    var enumerator = list.GetEnumerator();
    while (enumerator.MoveNext())
    {
        var listElement = enumerator.Current;
        Console.WriteLine(listElement + " ");
        list = list.Where(x => x != listElement).ToList();
    }
    enumerator.Dispose();

    Console.WriteLine("Count: " + list.Count);
}
Lee Campbell
  • 10,631
  • 1
  • 34
  • 29
2

Code shown never "modifies collection" in common meaning of that phrase (add/remove elements from existing collection), instead it creates new collection. As result there is no "collection modified" exceptions that you probably expect.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
0

In fact collection is not being modified as you are not adding/removing any item from the collection. In terms of reference to list variable, I do agree with Lee i.e. the loop is keeping the reference to the original enumerator.

Sami
  • 3,686
  • 4
  • 17
  • 28
0

Because foreach uses an enumerator, and enumerators can't change the underlying collection, but can, however, change any objects referenced by an object in the collection. Refer the link. Also an interesting article worth reading to understand the behavior

Community
  • 1
  • 1
Mukul Varshney
  • 3,131
  • 1
  • 12
  • 19