当枚举项发生变化时,是否会影响枚举?

发布于 2024-07-26 12:23:27 字数 313 浏览 3 评论 0原文

想象一下,在

foreach(var item in enumerable)

可枚举项发生变化时。 会影响当前的foreach吗?

示例:

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

它会永远循环吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

林空鹿饮溪 2024-08-02 12:23:27

一般来说,它应该抛出异常。
GetEnumerator() 的 List 实现 提供一个 Enumerator 对象,其 MoveNext() 方法如下所示(来自 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;
}

list._version 在每次修改 List 的操作中都会被修改(递增)。

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.

可是我不能没有你 2024-08-02 12:23:27

取决于枚举器的性质。 当集合更改时,其中许多会抛出异常。

例如,如果集合在枚举期间发生更改,List 会抛出 InvalidOperationException

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.

安稳善良 2024-08-02 12:23:27

Microsoft 的 IEnumerable 文档[和 IEnumerable——非通用名称将同时引用两者]建议,每当实现这些接口的对象发生更改时,它都应该失效它之前生成的任何 IEnumerator [IEnumerator] 实例,导致它们在将来的访问尝试中抛出 InvalidOperationException。 尽管 Microsoft 的文档中没有记录这种立场的任何变化,但他们的 IEnumerable 的实际实现似乎遵循一个更宽松的规则,即如果底层集合被修改; 如果它不能“明智地”运行,它应该抛出 InvalidOperationException 。 不幸的是,由于该规则没有明确说明,而是从其类的行为中推断出来,因此尚不清楚“合理”行为到底意味着什么。

我所知道的所有 Microsoft 类如果不能满足以下条件,在更改集合时都会抛出异常:

  1. 在整个枚举过程中未修改的任何项目将仅返回一次。
  2. 在枚举过程中添加或删除的项目最多返回一次,但是如果在枚举过程中删除并重新添加对象,则每次重新添加都可以被视为创建一个新的“项目”。
  3. 如果集合保证按排序顺序返回内容,则即使插入和删除项目也必须满足该保证[例如,如果“Fred”被添加到按字母顺序排序的列表中,并且“George”已被枚举,“ Fred”不得出现在该枚举期间]。

如果有一些方法可以让集合报告它们是否可以满足上述标准(即使在修改时也不会抛出异常),那将会很有帮助,因为当尝试删除满足特定标准的所有项目时,它们可能非常有用。

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.

醉态萌生 2024-08-02 12:23:27

这完全取决于 IEnumerable 的实现方式。

对于 List,它将抛出 IllegalOperationException。 但不要依赖 IEnumarable 的这种行为。 有些循环会无限循环,并且会很快抛出 OutOfMemory 异常。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文