1

I have a list with some old values that I want to delete, but it throws a System.InvalidOperatonException saying the collection was changed after creating an object. If I don't use the else statement, it is working all right.

foreach (var item in list) // here is exception
{
    if (DateTime.Parse(item.Key.ToShortDateString()) > DateTime.Parse("12.09.2020"))
    {
        panel.Controls.Add(new Label()
        {
            Text = item.Key.ToString().Remove(10) + "\n" + item.Key.ToString().Remove(0, 10) + "\n" + item.Value.ToString(),
            AutoSize = true
        });
        month.AddBoldedDate(item.Key);
    }
    else
    {
        list.Remove(item.Key); // I want to delete an old element
    }
}

How can I fix this problem?

CarenRose
  • 1,266
  • 1
  • 12
  • 24
Alex
  • 146
  • 9
  • https://stackoverflow.com/q/604831/1070452 – Ňɏssa Pøngjǣrdenlarp May 19 '20 at 16:28
  • 1
    change ``foreach (var item in list)`` to `foreach (var item in list.ToList())` – Mohammed Sajid May 19 '20 at 16:35
  • When you have items in a list like 3,4,5,6,7 and you remove item 5 then you end up with 3,4,6,7 and you skip the 6 using a foreach loop. So instead use for(int i = list.Count - 1; i >= 0; i--) { var item = list[i]}. Starting from the end of the list and moving towards then beginning will solve issue. – jdweng May 19 '20 at 16:36
  • foreach (var item in list) to foreach (var item in list.ToList()) it is working. – Alex May 19 '20 at 17:12

3 Answers3

0

Instead of removing elements while you're iterating over the list, you should remove them before that iteration like this:

list.RemoveAll(item => DateTime.Parse(item.Key.ToShortDateString()) > DateTime.Parse("12.09.2020"));

At this point all of those items are removed and you can continue with your loop without the else statement:

foreach (var item in list)
{
    panel.Controls.Add(new Label()
    {
        Text = item.Key.ToString().Remove(10) + "\n" + item.Key.ToString().Remove(0, 10) + "\n" + item.Value.ToString(),
        AutoSize = true
    });
    month.AddBoldedDate(item.Key);
}
CarenRose
  • 1,266
  • 1
  • 12
  • 24
Jakub Kozera
  • 3,141
  • 1
  • 13
  • 23
0

You cannot change a List when enumerating it. You should iterate on the list on items to remove.

        foreach(var item in list)
        {
            //...
            else
            {
                keysToRemove.Add(item.Key);
            }
        }

        foreach(var key in keysToRemove)
        {
            list.Remove(key);
        }
Khaled
  • 317
  • 2
  • 7
0

In foreach loops, the compiler in the background is creating an 'enumerator' - a structure that moves through the set of items 1 item at a time, and it feeds those items into the loop body.

If you alter items in the set of items while you are in the loop, this can have unpredictable consequences. To avoid this issue, create a copy of the list that you don't modify and use that as the basis for the loop, then modify the original:

// use list.ToList() to create a second copy of the list
// that will not change when you modify the original
foreach(var item in list.ToList())
{
  // ... existing code
}
otto-null
  • 593
  • 3
  • 15