收集被修改; 枚举操作可能无法在ArrayList中执行

Ric*_*rdo 78 c# collections enumeration exception

我正在尝试删除一个项目ArrayList,我得到这个例外:
Collection was modified; enumeration operation may not execute.

有任何想法吗?

Mar*_*ell 191

您正在删除该项目foreach,是吗?简单地说,你不能.这里有一些常见的选择:

  • 使用List<T>RemoveAll谓词
  • 按索引向后迭代,删除匹配的项目

    for(int i = list.Count - 1; i >= 0; i--) {
        if({some test}) list.RemoveAt(i);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用foreach,并将匹配的项目放入第二个列表; 现在枚举第二个列表并从第一个列表中删除这些项目(如果你看到我的意思)

  • 如果集合不是那么大,那么简单的.ToArray()并且枚举它也可能足够好. (4认同)
  • 这是非常整洁,我一直在迭代前进和有条件地减少`i`,以便下次增加它将指向删除后的项目.这避免了额外的步骤. (2认同)

Wil*_*ill 24

这是一个例子(抱歉任何错别字)

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);
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您使用3.5,Linq使第一点更容易:

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

foreach (var item in itemsToRemove) {
  originalArrayList.Remove(item);
}
Run Code Online (Sandbox Code Playgroud)

将"..."替换为确定是否应删除项目的条件.

  • 如果您使用“通用列表”(我将其解释为`List&lt;T&gt;`),那么只需使用`list.RemoveAll(item =&gt; ...)`。 (2认同)

ozc*_*cho 8

一种方法是将要删除的项目添加到新列表中.然后浏览并删除这些项目.


Joe*_*e B 8

我喜欢使用循环向后迭代for,但与之相比,这可能会变得乏味foreach.我喜欢的一个解决方案是创建一个向后遍历列表的枚举器.您可以在ArrayList或上将其实现为扩展方法List<T>.实施ArrayList方法如下.

    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];
        }
    }
Run Code Online (Sandbox Code Playgroud)

实现List<T>类似.

    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];
        }
    }
Run Code Online (Sandbox Code Playgroud)

下面的示例使用枚举器从a中删除所有偶数整数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);
    }
Run Code Online (Sandbox Code Playgroud)


3Da*_*ave 5

不要修改循环遍历列表的循环内的列表.

相反,使用a for()while()带索引,在列表中向后移动.(这样可以在不获取无效索引的情况下删除内容.)

var foo = new List<Bar>();

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


Kev*_*eus 5

我错过了什么吗?如果我错了,有人纠正我。

list.RemoveAll(s => s.Name == "Fred");
Run Code Online (Sandbox Code Playgroud)