When items change while being enumerated does it affects the enumeration?

两盒软妹~` 提交于 2019-12-08 16:33:41

问题


Imagine that during a

foreach(var item in enumerable)

The enumerable items change. It will affect the current foreach?

Example:

var enumerable = new List<int>();
enumerable.Add(1);
Parallel.ForEach<int>(enumerable, item =>
{ 
     enumerable.Add(item + 1);
});

It will loop forever?


回答1:


Generally, it should throw an exception. The List<T> implementation of GetEnumerator() Provides an Enumerator<T> object whose MoveNext() method looks like this (from Reflector):

public bool MoveNext()
{
    List<T> list = this.list;
    if ((this.version == list._version) && (this.index < list._size))
    {
        this.current = list._items[this.index];
        this.index++;
        return true;
    }
    return this.MoveNextRare();
}


private bool MoveNextRare()
{
    if (this.version != this.list._version)
    {
        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
    }
    this.index = this.list._size + 1;
    this.current = default(T);
    return false;
}

The list._version is modified (incremented) on each operation which modifies the List.




回答2:


Depends on the nature of the enumerator. Many of them throw exception when the collection changes.

For instance, List<T> throws an InvalidOperationException if the collection changes during enumeration.




回答3:


This fully depends on how IEnumerable is implemented.

With a List, It will throw an IllegalOperationException. But don't rely on this behaviour for IEnumarables. Some loop endless and will throw an OutOfMemoryexception quickly.




回答4:


Microsoft's documentation for IEnumerable [and IEnumerable<T>--non-generic names will refer to both] recommends that any time an object implementing those interfaces is changed, it should invalidate any instances of IEnumerator [IEnumerator<T>] which it has previously produced, causing them to throw InvalidOperationException on future access attempts. Although nothing in Microsoft's documentation has documented any change from this stance, their actual implementations of IEnumerable seem to follow a looser rule, which is that an IEnumerator should not behave nonsensically if the underlying collection is modified; it should throw InvalidOperationException if it can't behave "sensibly". Unfortunately, since that rule is not explicitly stated but rather inferred from the behavior of their classes, it's not clear what exactly "sensible" behavior should mean.

All of the Microsoft classes that I know of will will throw an exception when a collection is changed if they cannot meet the following criteria:

  1. Any item which exists unmodified throughout an enumeration will be returned exactly once.
  2. An item which is added or deleted during enumeration shall be returned at most once, but if an object is removed and re-added during enumeration, each re-addition may be regarded as creating a new "item".
  3. If a collection guarantees to return things in a sorted sequence, that guarantee must be met even if items are inserted and removed [e.g. if an "Fred" is added to an alphabetically-sorted list, and "George" has already been enumerated, "Fred" must not appear during that enumeration].

It would be helpful if there were some means via which collections could report whether they can satisfy the above criteria (without throwing exceptions) even when modified, since they can be very useful when trying to e.g. remove all items which meet a certain criterion.



来源:https://stackoverflow.com/questions/1114735/when-items-change-while-being-enumerated-does-it-affects-the-enumeration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!