See the following code:
List list = new List();
for (int i = 1; i < 10; i++)
{
list.Add(i);
}
foreach (int i in list)
{
list.Remove(i);
}
[/source]
Do you see anything wrong in this piece of code? No? Okay.
Execute this code and you will get a System.InvalidOperationException with the message “Collection was modified; enumeration operation may not execute.”
The first time foreach loop executes, it deletes the first item and in the second iteration, this nasty exception is thrown. Reason? You deleted the first item and the list has changed. If not for the InvalidOperationException , you could have got a IndexOutOfRange exception while traversing the list.
So, how does one delete some items in the list while iterating through the list? I faced this problem in my project today and I couldn’t come up with an elegant solution. I did come up with a hack. I identify all items that need to be deleted and mark them with a flag (I need one iteration here). In another iteration, I create a new list and copy all those items which are not marked.
Sorry, I couldn’t come up with something better. If you have a solution or a better fix, please do let me know. Please note that if I want to remove all items, I can use list.Clear(). I am talking about a scenario where I want to delete only a select few items.
Update:
I read somewhere that if you use for loop instead of foreach, this problem does not arise. True, you will not get an exception, but you might not delete the items that you actually want to delete. Let’s see what happens in our case.
List list = new List();
for (int i = 1; i < 10; i++)
{
list.Add(i);
}
for (int i = 0; i < list.Count; i++)
{
int remove = list[i];
list.Remove(remove);
}
[/source]
You will delete items 1, 3, 5, 7 and 9. After the for loop exits, your list will still have 2, 4, 6 and 8. Surprised?
Let's see why this is so.
First iteration: i = 0, remove = 1. Deleted item = 1 Once you delete this item, the list has changed. So, the first element in the list is now 2.
Second iteration: i = 1, remove = 3. Deleted item = 3
Third iteration: i = 2, remove = 5. Deleted item = 5
and so on….
So, replacing foreach with a for is not a solution.