17

私はこれQueues<T>まで実際に使用したことがないので、明らかな何かが欠けている可能性があります。私はQueue<EnemyUserControl>このように(すべてのフレームで)反復しようとしています:

foreach (var e in qEnemy)
{
     //enemy AI code
}

敵が死ぬと、敵のユーザーコントロールは、私がサブスクライブしたイベントを発生させ、これを実行します(キュー内の最初の敵は設計により削除されます)。

void Enemy_Killed(object sender, EventArgs e)
{      
     qEnemy.Dequeue();

     //Added TrimExcess to check if the error was caused by NULL values in the Queue (it wasn't :))
     qEnemy.TrimExcess();
}

ただし、Dequeueメソッドが呼び出された後InvalidOperationExceptionforeachループが発生します。代わりに使用する場合Peek、エラーは発生しないため、Dequeueはオブジェクトを削除するため、キュー自体の変更に何らかの影響を与える必要があります。私の最初の推測では、列挙子によって繰り返されているコレクションを変更していると文句を言っていますが、デキューはループの外で実行されていますか?

この問題を引き起こしている可能性のあるアイデアはありますか?

ありがとう

4

6 に答える 6

31

私はこれが古い投稿であることを知っていますが、次はどうですか?

var queue = new Queue<int>();
queue.Enqueue(1);
queue.Enqueue(2);

while (queue.Count > 0)
{
  var val = queue.Dequeue();
}

乾杯

于 2013-11-25T12:29:47.963 に答える
21

foreachループ内のキューを変更しています。これが例外の原因です。
問題を示すための簡略化されたコード:

var queue = new Queue<int>();
queue.Enqueue(1);
queue.Enqueue(2);

foreach (var i in queue)
{
    queue.Dequeue();
}

ToList()考えられる解決策は、次のように追加することです。

foreach (var i in queue.ToList())
{
    queue.Dequeue();
}
于 2011-06-04T01:37:51.233 に答える
5

古い投稿ですが、もっと良い答えを提供すると思いました:

var queue = new Queue<int>();
queue.Enqueue(1);
queue.Enqueue(2);


while (queue?.Count > 0))
{
  var val = queue.Dequeue();
}

DarkUrseの元の回答はdo/whileを使用しており、空のキューでデキューしようとしたときにキューが空の場合は例外が発生するため、nullキューに対する保護も追加されました

于 2018-07-10T11:52:43.700 に答える
1

これは、列挙子の典型的な動作です。ほとんどの列挙子は、基になるコレクションが静的なままである場合にのみ正しく機能するように設計されています。コレクションの列挙中にコレクションが変更さMoveNextれた場合、ブロックによって挿入される次のへの呼び出しにより、foreachこの例外が生成されます。

Dequeue操作は明らかにコレクションを変更し、それが問題の原因です。回避策は、ターゲットコレクションから削除する各アイテムを2番目のコレクションに追加することです。ループが完了したら、2番目のコレクションを循環して、ターゲットから削除できます。

Dequeueただし、この操作では次の項目しか削除されないため、少なくともこれは少し厄介かもしれません。任意の削除を可能にする別のコレクションタイプに切り替える必要がある場合があります。

を使用したい場合は、Queue各アイテムをデキューし、削除してはならないアイテムを条件付きで再キューに入れる必要があります。再キューイングから除外してもよいアイテムを追跡するために、2番目のコレクションが引き続き必要です。

于 2011-06-04T01:37:50.313 に答える
0

要素を繰り返し処理している間は、コレクションから要素を削除することはできません。

私が見つけた最善の解決策は、「List <> toDelete」を使用して、削除したいものをそのリストに追加することです。foreachループが終了したら、次のようにtoDeleteリストの参照を使用してターゲットコレクションから要素を削除できます。

foreach (var e in toDelete)
    target.Remove(e);
toDelete.Clear();

これはキューであるため、デキューする回数を整数でカウントし、単純なforループを使用して後で実行できる場合があります(この点に関しては、キューの経験はあまりありません)。

于 2011-06-04T01:39:40.187 に答える
0

コレクションをどこで変更するかは関係ありません。メンバーを列挙しているときにコレクションが変更されると、例外が発生します。Queueロックを使用して、反復するとき、または.NET 4.0を使用している場合は、コレクションを変更しないようにすることができますConcurrentQueue

于 2011-06-04T01:40:31.403 に答える