是否有任何C#集合,其中修改不会使迭代器失效?

Phi*_*ung 10 .net c# collections iterator

C#Collections库中是否有任何数据结构,其中结构的修改不会使迭代器失效?

考虑以下:

List<int> myList = new List<int>();
myList.Add( 1 );
myList.Add( 2 );
List<int>.Enumerator myIter = myList.GetEnumerator();
myIter.MoveNext();  // myIter.Current == 1
myList.Add( 3 );
myIter.MoveNext();  // throws InvalidOperationException
Run Code Online (Sandbox Code Playgroud)

Dan*_*Tao 11

是的,看一下System.Collections.Concurrent.NET 4.0 中的命名空间.

请注意,对于此命名空间中的某些集合(例如ConcurrentQueue<T>),这仅通过在有问题的集合的"快照"上公开枚举器来工作.

MSDN文档ConcurrentQueue<T>:

枚举表示队列内容的时刻快照.调用GetEnumerator后,它不会反映对集合的任何更新.枚举器可以安全地与队列的读取和写入同时使用.

但是,并非所有集合都是如此.ConcurrentDictionary<TKey, TValue>例如,为您提供一个枚举器,用于在调用之间维护对底层集合的更新MoveNext.

MSDN文档ConcurrentDictionary<TKey, TValue>:

从字典返回的枚举器可以安全地与字典的读写一起使用,但它并不代表字典的即时快照.通过枚举器公开的内容可能包含在调用GetEnumerator后对字典所做的修改.

如果你没有 4.0,那么我认为其他的是正确的,并且.NET没有提供这样的集合.但是,您可以通过执行相同的ConcurrentQueue<T>操作(迭代快照)来构建自己的.


And*_*bel 8

根据这篇关于IEnumeratorMSDN文章,IEnumerable的所有实现都需要您找到的失效行为.

只要集合保持不变,枚举器仍然有效.如果对集合进行了更改,例如添加,修改或删除元素,则枚举数将无法恢复,并且下一次调用MoveNext或Reset会引发InvalidOperationException.如果在MoveNext和Current之间修改了集合,则Current返回它所设置的元素,即使枚举器已经失效.

  • 那么,他们违反了自己的指导方针.`System.Collections.Concurrent`中的所有集合都允许在调用`MoveNext`之间修改集合. (6认同)

Tom*_*cek 5

支持这种行为需要一些相当复杂的内部处理,因此大多数集合都不支持这种情况(我不确定Concurrent命名空间).

但是,您可以使用不可变集合很好地模拟此行为.它们不允许您按设计修改集合,但您可以稍微不同的方式使用它们,这种处理允许您同时使用枚举器而无需复杂处理(在Concurrent集合中实现).

您可以轻松地实现这样的一个集合,或者您可以使用FSharpList<T>FSharp.Core.dll(不是.NET 4.0标准的一部分,尽管):

open Microsoft.FSharp.Collections;

// Create immutable list from other collection
var list = ListModule.OfSeq(anyCollection);
// now we can use `GetEnumerable`
var en = list.GetEnumerable();

// To modify the collection, you create a new collection that adds 
// element to the front (without actually copying everything)
var added = new FSharpList<int>(42, list);
Run Code Online (Sandbox Code Playgroud)

不可变集合的好处是你可以使用它们(通过创建副本)而不影响原始集合,因此你想要的行为是"免费".欲了解更多信息,Eric Lippert撰写了一系列精彩文章.


BFr*_*ree -1

使用for循环代替foreach,然后就可以修改它了。不过我不会建议这样做......

  • 但这并不能回答问题。他询问的是迭代器,而不仅仅是索引集合。 (2认同)