Collection was modified, enumeration operation may not execute

拟墨画扇 提交于 2019-12-09 17:14:30

问题


I have multithreads application and i get this error

************** 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()
   ...

I probably have problem with my collection, because on one thread i read my collection and on another thread i modify collection.

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


public void problem()
{
  foreach (GMapMarker m in Markers)
  {
    ...
  }
}

I am trying to lock collection with this code, but doesn't work.

public void problem()
    {
       lock(Markers)
       {
         foreach (GMapMarker m in Markers)
         {
           ...
         }
       }
    }

Any ideas to fix that problem?


回答1:


This is a pretty common mistake - modifying a collection whilst iterating it using foreach, keep in mind that foreach uses readonly IEnumerator instance.

Try to loop through the collection using for() with an extra index check so if the index is out of bounds you would be able to apply additional logic to handle it. You can also use LINQ's Count() as another loop exit condition by evaluating the Count value each time if the underlying enumeration does not implement ICollection:

If Markers implements IColletion - lock on SyncRoot:

lock (Markers.SyncRoot)

Use for():

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

You might find this post useful: How do foreach loops work in C#?




回答2:


You need to lock both on the reading and the writing side. Otherwise one of the threads will not know about the lock and will try to read/modify the collection, while the other is modifying/reading (respectively) with the lock held




回答3:


Try to read a clone of your collection

foreach (GMapMarker m in Markers.Copy())
{
   ...
}

this will create a new copy of your collection that will not be affected by another thread but may cause a performance issue in case of huge collection.

So I think it will be better if you locked the collection while reading and writing processes.




回答4:


You can use a foreach but you have to cast the collection to a list and use the dot operator to access the behavior methods.

Example: Markers.Tolist().ForEach(i => i.DeleteObject())

Not totally sure what you're doing with your collection. My example is assuming you just wanted to delete all items from the collection, but it can be applied to any behavior you're trying to do with your collection.




回答5:


I solved this problem by using

var data = getData();
lock(data)
{
    return getData().Select(x => new DisplayValueModel(x));
}

instead of

return getData().Select(x => new DisplayValueModel(x));


来源:https://stackoverflow.com/questions/9925083/collection-was-modified-enumeration-operation-may-not-execute

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!