16

コレクションを繰り返し処理しているときに、オブジェクトを削除しようとしています。しかし、私は例外を受けています。どうすればこれを達成できますか?これが私のコードです:

foreach (var gem in gems)
{
    gem.Value.Update(gameTime);

    if (gem.Value.BoundingCircle.Intersects(Player.BoundingRectangle))
    {
       gems.Remove(gem.Key); // I can't do this here, then How can I do?
       OnGemCollected(gem.Value, Player);
    }
}
4

5 に答える 5

29

foreach は、コレクションを変更せずに反復処理するように設計されています。

コレクションの反復処理中にコレクションからアイテムを削除するには、コレクションの最後から最初まで for ループを使用します。

for(int i = gems.Count - 1; i >=0 ; i--)
{
  gems[i].Value.Update(gameTime);

  if (gems[i].Value.BoundingCircle.Intersects(Player.BoundingRectangle))
  {
      Gem gem = gems[i];
      gems.RemoveAt(i); // Assuming it's a List<Gem>
      OnGemCollected(gem.Value, Player);
  }
 }

たとえば、次のdictionary<string, Gem>ように繰り返すことができます。

foreach(string s in gems.Keys.ToList())
{
   if(gems[s].BoundingCircle.Intersects(Player.BoundingRectangle))
   {
     gems.Remove(s);
   }
}
于 2013-05-11T12:27:06.563 に答える
1

最も簡単な方法は、@ IV4 が提案したことを行うことです。

foreach (var gem in gems.ToList())

は Dictionary をのToList()リストに変換するKeyValuePairので、問題なく動作します。

そのようにしたくないのは、比較的少数のアイテムのみを削除する大きな辞書があり、メモリの使用を減らしたい場合だけです。

その場合にのみ、次のいずれかのアプローチを使用します。


見つかったキーのリストを作成し、別のループでアイテムを削除します。

List<KeyType> keysToRemove = new List<KeyType>();

foreach (var gem in gems)
{
    gem.Value.Update(gameTime);

    if (gem.Value.BoundingCircle.Intersects(Player.BoundingRectangle))
    {
        OnGemCollected(gem.Value, Player);
        keysToRemove.Add(gem.Key);
    }
}

foreach (var key in keysToRemove)
    gems.Remove(key);

(使用しているキーのタイプはどこKeyTypeにありますか。正しいタイプに置き換えてください!)

または、を呼び出す前にgem を削除することが重要な場合はOnGemCollected()、(キーの typeTKeyと値の type を使用TValueして) 次のようにします。

var itemsToRemove = new List<KeyValuePair<TKey, TValue>>();

foreach (var gem in gems)
{
    gem.Value.Update(gameTime);

    if (gem.Value.BoundingCircle.Intersects(Player.BoundingRectangle))
        itemsToRemove.Add(gem);
}

foreach (var item in itemsToRemove)
{
    gems.Remove(item.Key);
    OnGemCollected(item.Value, Player);
}
于 2013-05-11T12:33:26.143 に答える
1

他の回答が言うように、 foreach は、ドキュメントに従ってコレクションを変更せずにコレクションを反復処理するために純粋に設計されています。

foreach ステートメントは、コレクションを反復処理して必要な情報を取得するために使用されますが、予期しない副作用を避けるために、コレクションの内容を変更するために使用しないでください。

これを行うには、for ループ(削除する必要があるコレクションのアイテムを格納する) を使用し、後でそれらをコレクションから削除する必要があります。

ただし、を使用しているList<T>場合は、次のことができます。

lines.RemoveAll(line => line.FullfilsCertainConditions());
于 2013-05-11T12:29:52.787 に答える
0

コレクションは、列挙子を使用した foreach ステートメントをサポートします。列挙子を使用してコレクション内のデータを読み取ることはできますが、基になるコレクションを変更するために使用することはできません。要素の追加、変更、または削除などの変更がコレクションに加えられた場合、列挙子は回復できないほど無効になり、次に MoveNext または Reset を呼び出すと InvalidOperationException がスローされます。コレクションの変更には for ループを使用します。

于 2013-05-11T12:33:10.220 に答える
0

foreach ループの代わりに for ループを使用する必要があります。こちらをご参照ください

于 2013-05-11T12:25:17.520 に答える