集合已修改,枚举操作可能无法执行
本文关键字:执行 操作 修改 枚举 集合 | 更新日期: 2023-09-27 18:29:19
我有多线程应用程序,我得到了这个错误
************** 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()
...
我可能对我的收藏有问题,因为在一个线程上我阅读了我的收藏,在另一个线程中我修改了收藏。
public readonly ObservableCollectionThreadSafe<GMapMarker> Markers = new ObservableCollectionThreadSafe<GMapMarker>();
public void problem()
{
foreach (GMapMarker m in Markers)
{
...
}
}
我正在尝试使用此代码锁定集合,但不起作用。
public void problem()
{
lock(Markers)
{
foreach (GMapMarker m in Markers)
{
...
}
}
}
有什么办法解决这个问题吗?
这是一个非常常见的错误-在使用foreach
迭代集合的同时修改集合,请记住foreach
使用只读IEnumerator
实例。
尝试使用带有额外索引检查的for()
循环遍历集合,这样,如果索引越界,您就可以应用额外的逻辑来处理它。如果底层枚举没有实现ICollection
:,您还可以通过每次评估Count
值来使用LINQ的Count()
作为另一个循环退出条件
如果Markers
在SyncRoot:上实现IColletion
锁定
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#中是如何工作的?
您需要在读取端和写入端进行锁定。否则,其中一个线程将不知道锁,并将尝试读取/修改集合,而另一个线程则使用锁持有的来修改/读取(分别)
尝试读取集合的克隆
foreach (GMapMarker m in Markers.Copy())
{
...
}
这将创建一个新的集合副本,该副本不会受到另一个线程的影响,但在大量集合的情况下可能会导致性能问题。
所以我认为如果你在阅读和写作过程中锁定收藏会更好。
这对我很有效。对Markers执行ToList()操作:foreach (GMapMarker m in Markers.ToList())
您可以使用foreach,但必须将集合强制转换为列表,并使用点运算符访问行为方法。
示例:Markers.Tolist().ForEach(i=>i.DeleteObject())
不完全确定你在用你的收藏品做什么。我的例子是假设您只想从集合中删除所有项目,但它可以应用于您试图对集合执行的任何行为。