I haven't used Queues<T>
to any real degree before, so I might be missing something obvious. I'm trying to iterate through a Queue<EnemyUserControl>
like this (every frame):
foreach (var e in qEnemy)
{
//enemy AI code
}
When an enemy dies, the enemy user control raises an event I've subscribed to and I do this (the first enemy in the queue is removed by design):
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();
}
However, after the Dequeue method is called, I get an InvalidOperationException
on the foreach
loop. When I use Peek
instead, there are no errors so it has to do something with the changing of the Queue itself since Dequeue removes the object.
My initial guess is that it's complaining that I'm modifying a collection which is being iterated by the Enumerator, but the dequeuing is being performed outside the loop?
Any ideas what could be causing this issue?
Thanks
I know this is an old post but what about the following :
var queue = new Queue<int>();
queue.Enqueue(1);
queue.Enqueue(2);
while (queue.Count > 0)
{
var val = queue.Dequeue();
}
Cheers
You are modifying queue inside of foreach
loop. This is what causes the exception.
Simplified code to demonstrate the issue:
var queue = new Queue<int>();
queue.Enqueue(1);
queue.Enqueue(2);
foreach (var i in queue)
{
queue.Dequeue();
}
Possible solution is to add ToList()
, like this:
foreach (var i in queue.ToList())
{
queue.Dequeue();
}
Old post but thought I would provide a better answer:
var queue = new Queue<int>();
queue.Enqueue(1);
queue.Enqueue(2);
while (queue?.Count > 0))
{
var val = queue.Dequeue();
}
As DarkUrse's original answer used a do/while and that would cause an exception if the queue is empty when trying to de-queue on the empty queue, also added a protection against a null queue
This is typical behavior of enumerators. Most enumerators are designed to function correctly only if the underlying collection remains static. If the collection is changed while enumerating a collection then the next call to MoveNext
, which is injected for you by the foreach
block, will generate this exception.
The Dequeue
operation obviously changes the collection and that is what is causing the problem. The workaround is to add each item you want removed from the target collection into a second collection. After the loop is complete you can then cycle through the second collection and remove from the target.
However, this might be a bit awkward, at the very least, since the Dequeue
operation only removes the next item. You may have to switch to a different collection type which allows arbitrary removals.
If you want to stick with a Queue
then you will be forced to dequeue each item and conditionally re-queue those items which should not be removed. You will still need the second collection to keep track of the items that are okay to omit from the re-queueing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With