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>),这仅通过在有问题的集合的"快照"上公开枚举器来工作.
枚举表示队列内容的时刻快照.调用GetEnumerator后,它不会反映对集合的任何更新.枚举器可以安全地与队列的读取和写入同时使用.
但是,并非所有集合都是如此.ConcurrentDictionary<TKey, TValue>例如,为您提供一个枚举器,用于在调用之间维护对底层集合的更新MoveNext.
从MSDN文档ConcurrentDictionary<TKey, TValue>:
从字典返回的枚举器可以安全地与字典的读写一起使用,但它并不代表字典的即时快照.通过枚举器公开的内容可能包含在调用GetEnumerator后对字典所做的修改.
如果你没有 4.0,那么我认为其他的是正确的,并且.NET没有提供这样的集合.但是,您可以通过执行相同的ConcurrentQueue<T>操作(迭代快照)来构建自己的.
根据这篇关于IEnumerator的MSDN文章,IEnumerable的所有实现都需要您找到的失效行为.
只要集合保持不变,枚举器仍然有效.如果对集合进行了更改,例如添加,修改或删除元素,则枚举数将无法恢复,并且下一次调用MoveNext或Reset会引发InvalidOperationException.如果在MoveNext和Current之间修改了集合,则Current返回它所设置的元素,即使枚举器已经失效.
支持这种行为需要一些相当复杂的内部处理,因此大多数集合都不支持这种情况(我不确定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撰写了一系列精彩文章.
| 归档时间: |
|
| 查看次数: |
2463 次 |
| 最近记录: |