2016-09-02 9 views
0

これは私にとって大きな混乱でした。私は次のコードを持っています:1つのコレクションから削除されたアイテムは、暗黙的に2番目のコレクションからも削除されます。なぜですか?

IEnumerable<WorkflowStateData> data = model.Data.Except(
      request.WorkflowState.CustomData.Select(x => new Model.WorkflowStateData {Key = x.Key}), 
      new WorkflowStateDataEqualityComparer()); 
     foreach (var item in data) // makes the comparison (and exception) based on the value of property 'Key' 
     { 
      model.Data.Remove(item); 
      stateDataSet.Remove(item); 
     } 

これは、アイテムの新しいコレクションを作成し、foreachを使用して列挙するために使用する必要があります。元のコレクションからアイテムを削除する必要がありますが、元のコレクションと "データ"コレクションの両方から削除してInvalidOperationExceptionをスローします。コレクションが変更されました。どうして?

+0

メモリ内の同じオブジェクトへの参照です –

答えて

0

答えはかなりシンプルですが、その裏切りの "var"キーワードを使用しているため明らかではありません。 ExceptはICollectionではなくIEnumerableを返します。 IEnumerableは、特定のコレクションへのビューとして想像することができます、それは独自のコレクションではありません。アイテムが元のコレクションから削除されたとき、私の列挙も変更されました。

1

Enumerable.Exceptは、設定された差異のIEnumerable<T>を返しますが、それは延期されます。つまり、依然としてクエリのみを意味します。だから毎回dataに「触れる」と言いますが、このクエリを実行します。だから、もしあなたがToListToArrayToLookupまたはToDictionaryを使って(または別のコレクションにforeach -loopの結果を追加して)使用しなければならない "マテリアライズド"コレクションが必要な場合。

現在、foreachで列挙しているコレクションを変更しようとすると、例外が発生することさえあります。今、あなたはリストから削除せずに元のコレクションからオブジェクトを削除することができ

List<WorkflowStateData> data = model.Data.Except(
     request.WorkflowState.CustomData.Select(x => new Model.WorkflowStateData {Key = x.Key}), 
     new WorkflowStateDataEqualityComparer()) 
    .ToList(); 

:だから、あなたはそれが元だ修正した場合afffectedされていない本当のコレクションを作成するためにToListを使用することができます。

LINQの遅延実行/ eager評価についてお読みください。

関連する問題