是否有任何 C# 集合的修改不会使迭代器失效?
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
Are there any data structures in the C# Collections library where modification of the structure does not invalidate iterators?
Consider the following:
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
是的,请查看
System.Collections.Concurrent .NET 4.0 中的
命名空间。请注意,对于此命名空间中的某些集合(例如,
ConcurrentQueue
),这通过仅在相关集合的“快照”上公开枚举器来实现。来自 关于 ConcurrentQueue的 MSDN 文档 :
但并非所有集合都是如此。例如,
ConcurrentDictionary
为您提供了一个枚举器,用于在调用MoveNext
之间维护底层集合的更新。来自 关于
ConcurrentDictionary
:如果您没有 4.0,那么我认为其他人是对的,.NET 没有提供这样的集合。不过,您始终可以通过执行
ConcurrentQueue
所做的相同操作(迭代快照)来构建自己的队列。Yes, take a look at the
System.Collections.Concurrent
namespace in .NET 4.0.Note that for some of the collections in this namespace (e.g.,
ConcurrentQueue<T>
), this works by only exposing an enumerator on a "snapshot" of the collection in question.From the MSDN documentation on
ConcurrentQueue<T>
:This is not the case for all of the collections, though.
ConcurrentDictionary<TKey, TValue>
, for instance, gives you an enumerator that maintains updates to the underlying collection between calls toMoveNext
.From the MSDN documentation on
ConcurrentDictionary<TKey, TValue>
:If you don't have 4.0, then I think the others are right and there is no such collection provided by .NET. You can always build your own, however, by doing the same thing
ConcurrentQueue<T>
does (iterate over a snapshot).根据这篇关于 IEnumerator 的 MSDN 文章,失效行为您发现 IEnumerable 的所有实现都需要它。
According to this MSDN article on IEnumerator the invalidation behaviour you have found is required by all implementations of IEnumerable.
支持此行为需要一些相当复杂的内部处理,因此大多数集合不支持此行为(我不确定
Concurrent
命名空间)。但是,您可以使用不可变集合很好地模拟这种行为。它们不允许您按设计修改集合,但您可以以稍微不同的方式使用它们,并且这种处理允许您同时使用枚举器,而无需复杂的处理(在
>并发
集合)。您可以轻松实现这样的集合,也可以使用
FSharp.Core.dll
中的FSharpList
(尽管不是 .NET 4.0 的标准部分):不可变集合的好处是您可以使用它们(通过创建副本)而不影响原始集合,因此您想要的行为是“免费”的。有关详细信息,请访问 Eric Lippert 的精彩系列。
Supporting this behavior requires some pretty complex internal handling, so most of the collections don't support this (I'm not sure about the
Concurrent
namespace).However, you can very well simulate this behavior using immutable collections. They don't allow you to modify the collection by design, but you can work with them in a slightly different way and this kind of processing allows you to use enumerator concurrently without complex handling (implemented in
Concurrent
collections).You can implement a collection like that easily, or you can use
FSharpList<T>
fromFSharp.Core.dll
(not a standard part of .NET 4.0 though):The benefit of immutable collections is that you can work with them (by creating copies) without affecting the original one, and so the behavior you wanted is "for free". For more information, there is a great series by Eric Lippert.
执行此操作的唯一方法是在迭代列表之前复制列表:
The only way to do this is to make a copy of the list before you iterate it:
不,它们不存在。当结构发生变化时,所有 C# 标准集合都会使分子失效。
No, they do not exist. ALl C# standard collections invalidate the numerator when the structure changes.
使用for循环代替foreach,然后就可以修改它了。但我不会建议这样做......
Use a for loop instead of a foreach, and then you can modify it. I wouldn't advise it though....