Collection was modified; enumeration operation may not execute in ArrayList

Viewed 180671

I'm trying to remove an item from an ArrayList and I get this Exception:
Collection was modified; enumeration operation may not execute.

Any ideas?

9 Answers

You are removing the item during a foreach, yes? Simply, you can't. There are a few common options here:

  • use List<T> and RemoveAll with a predicate
  • iterate backwards by index, removing matching items

    for(int i = list.Count - 1; i >= 0; i--) {
        if({some test}) list.RemoveAt(i);
    }
    
  • use foreach, and put matching items into a second list; now enumerate the second list and remove those items from the first (if you see what I mean)

Here's an example (sorry for any typos)

var itemsToRemove = new ArrayList();  // should use generic List if you can

foreach (var item in originalArrayList) {
  if (...) {
    itemsToRemove.Add(item);
  }
}

foreach (var item in itemsToRemove) {
  originalArrayList.Remove(item);
}

OR if you're using 3.5, Linq makes the first bit easier:

itemsToRemove = originalArrayList
  .Where(item => ...)
  .ToArray();

foreach (var item in itemsToRemove) {
  originalArrayList.Remove(item);
}

Replace "..." with your condition that determines if item should be removed.

One way is to add the item(s) to be deleted to a new list. Then go through and delete those items.

I like to iterate backward using a for loop, but this can get tedious compared to foreach. One solution I like is to create an enumerator that traverses the list backward. You can implement this as an extension method on ArrayList or List<T>. The implementation for ArrayList is below.

    public static IEnumerable GetRemoveSafeEnumerator(this ArrayList list)
    {
        for (int i = list.Count - 1; i >= 0; i--)
        {
            // Reset the value of i if it is invalid.
            // This occurs when more than one item
            // is removed from the list during the enumeration.
            if (i >= list.Count)
            {
                if (list.Count == 0)
                    yield break;

                i = list.Count - 1;
            }

            yield return list[i];
        }
    }

The implementation for List<T> is similar.

    public static IEnumerable<T> GetRemoveSafeEnumerator<T>(this List<T> list)
    {
        for (int i = list.Count - 1; i >= 0; i--)
        {
            // Reset the value of i if it is invalid.
            // This occurs when more than one item
            // is removed from the list during the enumeration.
            if (i >= list.Count)
            {
                if (list.Count == 0)
                    yield break;

                i = list.Count - 1;
            }

            yield return list[i];
        }
    }

The example below uses the enumerator to remove all even integers from an ArrayList.

    ArrayList list = new ArrayList() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    foreach (int item in list.GetRemoveSafeEnumerator())
    {
        if (item % 2 == 0)
            list.Remove(item);
    }

Don't modify the list inside of a loop which iterates through the list.

Instead, use a for() or while() with an index, going backwards through the list. (This will let you delete things without getting an invalid index.)

var foo = new List<Bar>();

for(int i = foo.Count-1; i >= 0; --i)
{
  var item = foo[i];
  // do something with item
}

Instead of foreach(), use a for() loop with a numeric index.

Related