集合已修改,枚举操作可能无法执行
我有multithreading应用程序,我得到这个错误
************** Exception Text ************** System.InvalidOperationException: Collection was modified; enumeration operation may not execute. at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) at System.Collections.Generic.List`1.Enumerator.MoveNextRare() at System.Collections.Generic.List`1.Enumerator.MoveNext() ...
我的collections可能有问题,因为在一个线程上我读取了我的collections,在另一个线程上我修改了collections。
public readonly ObservableCollectionThreadSafe Markers = new ObservableCollectionThreadSafe(); public void problem() { foreach (GMapMarker m in Markers) { ... } }
我试图用这段代码锁定集合,但不起作用。
public void problem() { lock(Markers) { foreach (GMapMarker m in Markers) { ... } } }
有什么想法来解决这个问题?
这是非常常见的错误 – 在使用foreach
迭代它时修改集合,请记住foreach
使用只读IEnumerator
实例。
使用带有额外索引检查的for()
尝试循环遍历集合for()
这样如果索引超出范围 – 你可以应用额外的逻辑来处理这个,也可以作为循环退出条件你可以使用LINQ Count()
来评估计数值每次如果基础枚举没有实现ICollection
:
如果Markers
实现IColletion
– 锁定SyncRoot:
lock (Markers.SyncRoot)
for()
:
for (int index = 0; index < Markers.Count(); index++) { if (Markers>= Markers.Count()) { // TODO: handle this case to avoid run time exception } }
可能会发现这篇文章有用: foreach循环如何在C#中工作?
你需要锁定读数和写入方面。 否则其中一个线程将不知道锁定并将尝试读取/修改集合,而另一个线程正在修改/读取(分别)锁定
尝试阅读您的collections的克隆
foreach (GMapMarker m in Markers.Copy()) { ... }
这将创建您的集合的新副本,该副本不会受到另一个线程的影响,但在收集大量数据时可能会导致性能问题。
所以我认为如果你在阅读和编写过程中锁定集合会更好。
您可以使用foreach,但必须将集合强制转换为列表并使用点运算符来访问行为方法。
示例:Markers.Tolist()。ForEach(i => i.DeleteObject())
不完全确定你对你的collections品做了什么。 我的例子是假设您只想删除集合中的所有项目,但它可以应用于您尝试对集合执行的任何行为。
我通过使用解决了这个问题
var data = getData(); lock(data) { return getData().Select(x => new DisplayValueModel(x)); }
代替
return getData().Select(x => new DisplayValueModel(x));