Chris Kooken
Chris Kooken

Reputation: 33938

Error: Collection was modified; enumeration operation may not execute

I've been getting this exception out in the field. I don't understand how the collection can be modified while iterating. I copy everything to local variables at the start of the method.

  public void Flush() {
            var tempEntities = attachedEntities.Select(item => item).ToList();
            attachedEntities.Clear();

            var tempEntitiesToDelete = entitiesToDelete.Select(item => item).ToList();
            entitiesToDelete.Clear();

            foreach (var attachedEntity in tempEntities) {
                var isTransient = (bool)GetPrivateField(attachedEntity.GetType(), attachedEntity, "isTransient");
                if (isTransient)
                    db.Insert(attachedEntity);
                else
                    db.Update(attachedEntity);
            }

            foreach (var entity in tempEntitiesToDelete)
                db.Delete(entity);
        }

Stack Trace

System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
  at System.Collections.Generic.List`1 Enumerator[Compass.Mobile.Core.DataAccess.IEntity].VerifyState () [0x00000] in <filename unknown>:0 
  at System.Collections.Generic.List`1 Enumerator[Compass.Mobile.Core.DataAccess.IEntity].MoveNext () [0x00000] in <filename unknown>:0 
  at System.Linq.Enumerable <CreateSelectIterator>c__Iterator1D`2[Compass.Mobile.Core.DataAccess.IEntity,Compass.Mobile.Core.DataAccess.IEntity].MoveNext () [0x00000] in <filename unknown>:0 
  at System.Collections.Generic.List`1[Compass.Mobile.Core.DataAccess.IEntity].AddEnumerable (IEnumerable`1 enumerable) [0x00000] in <filename unknown>:0 
  at System.Collections.Generic.List`1[Compass.Mobile.Core.DataAccess.IEntity]..ctor (IEnumerable`1 collection) [0x00000] in <filename unknown>:0 
  at System.Linq.Enumerable.ToList[TSource] (IEnumerable`1 source) [0x00000] in <filename unknown>:0 
  at Compass.Mobile.Core.DataAccess.Session.Flush () [0x00000] in <filename unknown>:0 
  at Compass.Mobile.Core.DataAccess.Session.Commit () [0x00000] in <filename unknown>:0 
  at Compass.Mobile.Core.Bootstrap.CommandBus.Flush () [0x00000] in <filename unknown>:0 

Upvotes: 2

Views: 14186

Answers (2)

Dan Abramov
Dan Abramov

Reputation: 268293

Judging by the stack trace, it's not failing inside your foreach (or enumerating tempEntities which is a plain list) but inside one of ToList calls, when Select iterator's underlying list checks its state before moving on to next item.

This line in your stack trace makes me believe so:

at System.Linq.Enumerable <CreateSelectIterator>c__Iterator1D`2[Compass.Mobile.Core.DataAccess.IEntity,Compass.Mobile.Core.DataAccess.IEntity].MoveNext () [0x00000] in <filename unknown>:0 

Your foreach loop variable is just a list, so it doesn't go through Select. This leads me to believe that either attachedEntities or entitiesToDelete change while you're doing Select over them:

/* Failing here... */
var tempEntities = attachedEntities.Select(item => item).ToList();
attachedEntities.Clear();

/* ...or here*/
var tempEntitiesToDelete = entitiesToDelete.Select(item => item).ToList();
entitiesToDelete.Clear();

/* ...but not here! */
foreach (var attachedEntity in tempEntities) {
   // ...
}

It could very well be a concurrency issue.

By the way, you really don't need Select (item => item), it would just be an identity projection.

Upvotes: 2

Brian Mains
Brian Mains

Reputation: 50728

Replace this:

foreach (var entity in tempEntitiesToDelete)
     db.Delete(entity);

With:

for (var i = tempEntitiesToDelete.Count - 1; i >= 0; i--)
   db.Delete(tempEntitiesToDelete[i]);

I had this problem when I tried to delete while looping through; it was trying to modify the list of items. Therefore, looping backward fixed it for me.

Upvotes: 3

Related Questions