foreach 循环是否正确处理列表长度的变化?

does foreach loop handle Changes in list length correctly?

foreach 是否正确迭代灵活列表?

例如

//will iterate over all items in list?
foreach (var obj in list)
{
    //list length changes here
    //ex:

    list.Add(...);
    list.Remove(...);
    list.Concat(...);
    // and so on
}

如果是...怎么办?

根据 documentation,如果在循环内进行更改,则行为未定义。 undefined 表示对它能做的事情没有任何限制,没有"incorrect behavior"当行为未定义时...崩溃,做你想做的,发邮件给你的老板骂他下流的名字并退出,所有同样有效。我希望在这种情况下会发生崩溃,但同样,无论发生什么,都会发生并根据文档被视为 "correct"。

您在 foreach 循环中使用的集合是 immutable. As per MSDN

The foreach statement is used to iterate through the collection to get the information that you want, but can not be used to add or remove items from the source collection to avoid unpredictable side effects. If you need to add or remove items from the source collection, use a for loop.

但是根据这个 link看起来现在可以从 .Net 4.0

您不能在 foreach 语句中枚举集合时修改它。

您应该使用另一种模式来完成您想做的事情,因为 for each 不允许您更改要循环到的枚举器。

例如: 想象一下,如果你 运行 从一开始就对排序列表进行 foreach,你开始使用 key="A" 处理项目,然后转到 "B" 然后将 "C" 更改为 "B",会发生什么?您的列表已被重新使用,您不再知道您在循环什么以及您在哪里。

一般来说,你 "could" 用 for(int i=dictionary.count-1; i>=0; --i) 或类似的东西来做,但这也取决于你的上下文,我真的会尝试使用另一种方法。

内部工作: IEnumerator<t> 旨在启用迭代器模式来迭代元素集合,而不是长度索引。 IEnumerator<t> 包括两名成员。

  • 第一个是bool MoveNext()。使用这种方法,我们可以从集合中的一个元素移动到下一个元素,同时检测我们何时使用布尔值 return.

  • 枚举了每个项目
  • 第二个成员,只读 属性 称为 Current,returns 当前正在处理的元素。有了集合中的这两个成员 class,可以简单地使用 while 循环遍历集合。

此列表中的 MoveNext() 方法 returns false 当它移过集合末尾时。这取代了在循环时计算元素的需要。 (IEnumerator<t> 上的最后一个成员 Reset() 将重置枚举。)

您不能在同一集合的 for each 循环中更改集合。 如果需要,可以使用 for 循环来更改集合长度。