Why does List.ForEach allow its list to be modified?

前端 未结 4 1955
礼貌的吻别
礼貌的吻别 2021-01-31 13:02

If I use:

var strings = new List { \"sample\" };
foreach (string s in strings)
{
  Console.WriteLine(s);
  strings.Add(s + \"!\");
}
相关标签:
4条回答
  • 2021-01-31 13:46

    It's because the ForEach method doesn't use the enumerator, it loops through the items with a for loop:

    public void ForEach(Action<T> action)
    {
        if (action == null)
        {
            ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
        }
        for (int i = 0; i < this._size; i++)
        {
            action(this._items[i]);
        }
    }
    

    (code obtained with JustDecompile)

    Since the enumerator is not used, it never checks if the list has changed, and the end condition of the for loop is never reached because _size is increased at every iteration.

    0 讨论(0)
  • 2021-01-31 13:48

    List<T>.ForEach is implemented through for inside, so it does not use enumerator and it allows to modify the collection.

    0 讨论(0)
  • 2021-01-31 13:54

    Because the ForEach attached to the List class internally uses a for loop that is directly attached to its internal members -- which you can see by downloading the source code for the .NET framework.

    http://referencesource.microsoft.com/netframework.aspx

    Where as a foreach loop is first and foremost a compiler optimization but also must operate against the collection as an observer -- so if the collection is modified it throws an exception.

    0 讨论(0)
  • 2021-01-31 13:56

    We know about this issue, it was an oversight when it was originally written. Unfortunately, we can't change it because it would now prevent this previously working code from running:

            var list = new List<string>();
            list.Add("Foo");
            list.Add("Bar");
    
            list.ForEach((item) => 
            { 
                if(item=="Foo") 
                    list.Remove(item); 
            });
    

    The usefulness of this method itself is questionable as Eric Lippert pointed out, so we didn't include it for .NET for Metro style apps (ie Windows 8 apps).

    David Kean (BCL Team)

    0 讨论(0)
提交回复
热议问题