集合被修改,枚举操作可能无法执行

PAT*_*TO7 7 c# multithreading enumerator

我有多线程应用程序,我得到这个错误

************** 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()
   ...
Run Code Online (Sandbox Code Playgroud)

我的收藏可能有问题,因为在一个线程上我读取了我的收藏,在另一个线程上我修改了收藏.

public readonly ObservableCollectionThreadSafe<GMapMarker> Markers = new ObservableCollectionThreadSafe<GMapMarker>();


public void problem()
{
  foreach (GMapMarker m in Markers)
  {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

我试图用这段代码锁定集合,但不起作用.

public void problem()
    {
       lock(Markers)
       {
         foreach (GMapMarker m in Markers)
         {
           ...
         }
       }
    }
Run Code Online (Sandbox Code Playgroud)

有什么想法来解决这个问题?

sll*_*sll 11

这是一个非常常见的错误 - 在使用迭代时修改集合foreach,请记住foreach使用只读IEnumerator实例.

使用for()额外的索引检查尝试循环遍历集合,因此如果索引超出范围 - 您将能够应用其他逻辑来处理此问题,同样作为循环退出条件,您可以使用LINQ Count(),如果基础枚举执行,则每次都会评估计数值没有实施Count:

如果ICollection实现Markers- 锁定SyncRoot:

lock (Markers.SyncRoot)
Run Code Online (Sandbox Code Playgroud)

用途IColletion:

for (int index = 0; index < Markers.Count(); index++)
{
    if (Markers>= Markers.Count())
    {
       // TODO: handle this case to avoid run time exception
    }
}
Run Code Online (Sandbox Code Playgroud)

可能会发现这篇文章有用:foreach循环如何在C#中工作?


Att*_*ila 4

您需要在读取端和写入端都锁定。否则,其中一个线程将不知道锁,并将尝试读取/修改集合,而另一个线程则在持有锁的情况下(分别)修改/读取