Collection was modified, enumeration operation may not execute
Solution 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#?
Solution 2
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.
Solution 3
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
PATO7
Updated on July 19, 2022Comments
-
PATO7 almost 2 years
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?
-
Amir Ismail about 12 yearsbut if the modification was by deleting an item from the collection, that will throw an
IndexOutOfRange
exception -
sll about 12 yearsI mentioned extra index check to avoid this issue, will add sample, thanks for pointing to this
-
PATO7 about 12 yearsi thinking to replace foreach with for but then i thought if would be better to lock collection but don't work :/
-
Renatas M. about 12 years...and modify original collection.
-
Amir Ismail about 12 yearsyou are right, I think to use
.Copy
but it may cause a performance issue. -
PATO7 about 12 yearsint i = mapMarkers.Markers.IndexOf(oldMarker); if (i != -1) { mapMarkers.Markers[i] = newMarker; }
-
sll about 12 yearsSince
ObservableCollectionThreadSafe
is your custom collection class, please show code for Add/Remove, BTW have you lock onthis.SyncRoot
inside Add/Remove methods? -
sll about 12 yearstry out
lock(this.SyncRoot) { this.Add(item); }
inside a ObservableCollectionThreadSafe class, the same forRemove()
-
PATO7 about 12 yearsGMap.NET.ObjectModel.ObservableCollectionThreadSafe<T> does not contain a definition for 'SynRoot...
-
sll about 12 yearsDoes it inherited from ObservableCollection? If so, resolve syncRoot to local field as
this.syncRoot = (this as ICollection).SyncRoot
sinceICollection
implemented explicitly -
afterxleep over 5 yearsYep "reverting" to an ordinary for loop did the trick for me too.