2

私はこの例外を現場で出してきました。反復中にコレクションを変更する方法がわかりません。メソッドの開始時にすべてをローカル変数にコピーします。

  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);
        }

スタックトレース

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 
4

2 に答える 2

3

これを置き換えます:

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

と:

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

ループ中に削除しようとすると、この問題が発生しました。アイテムのリストを変更しようとしていました。したがって、後方にループすることで修正されました。

于 2013-02-08T19:06:40.697 に答える
2

スタックトレースから判断すると、イテレータの基になるリストが次の項目に進む前にその状態をチェックするときに、それはあなたの内部foreach(またはtempEntitiesプレーンリストであるものを列挙する)で失敗するのではなく、ToList呼び出しの1つで失敗します。Select

スタックトレースのこの行は、私にそう信じさせます:

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

foreachループ変数は単なるリストであるため、を通過しませんSelect。これは私にそれを信じさせるかattachedEntitiesentitiesToDeleteあなたがそれらをやっている間に変わるSelect

/* 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) {
   // ...
}

これは、並行性の問題である可能性が非常に高いです。

ちなみに、あなたは本当に必要ではありませんSelect (item => item)、それはただアイデンティティの投影になるでしょう。

于 2013-02-08T19:16:17.107 に答える