【问题标题】:Collection was modified; enumeration operation may not execute in ArrayList [duplicate]收藏已修改;枚举操作可能无法在 ArrayList 中执行 [重复]
【发布时间】:2011-01-02 17:02:01
【问题描述】:

我正在尝试从 ArrayList 中删除一个项目,但我得到了这个异常:
Collection was modified; enumeration operation may not execute.

有什么想法吗?

【问题讨论】:

  • 作为记录,除非您使用 .NET 1.0 或 1.1,否则您可能应该使用 List<T> 而不是 ArrayList
  • 为什么这个重复我在Application.Exit();有时收到这个错误,我没有操作任何集合或应用程序。
  • foreach(Ite​​mCollection item in ItemCollection.Values) To foreach(Ite​​mCollection s in ItemCollection.Values.ToList()) 问题是在 foreach 循环中正在修改 ItemCollection.Values。调用 ItemCollection.Values.ToList() 将subscribers.Values 的值复制到foreach 开头的单独列表中

标签: c# exception collections enumeration


【解决方案1】:

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

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

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

【讨论】:

  • 如果集合不是那么大,一个简单的 .ToArray() 并枚举它也可能足够好。
  • 这非常简洁,我一直在向前迭代并有条件地递减i,以便下次递增时,它将指向已删除项目之后的项目。这避免了额外的步骤。
  • 向后迭代工作正常。我会避免使用 .ToArray() ,因为它会为您的算法添加一个不必要的循环(一个用于将列表复制到数组,一个用于删除您感兴趣的项目)。
  • 添加 .ToList();到foreach中的数组然后你可以做你想做的事
  • 嗨,Marc,请告知为什么即使我从第一个列表中获得了新列表,我仍然会收到此错误,并枚举新列表我从旧列表中删除项目,但仍然会出现错误。仅当我将ToList 应用于新列表错误才会消失。但是不要枚举新列表已经使ToList 调用产生了什么?
【解决方案2】:

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

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);
}

或者,如果您使用的是 3.5,Linq 会让第一步变得更容易:

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

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

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

【讨论】:

  • 如果您使用“通用列表”(我将其解释为List<T>),那么只需使用list.RemoveAll(item => ...)
  • 我正在使用 Blazor,我正在执行 foreach 然后删除项目,但遇到了一个有趣的错误。这样做解决了我有趣的错误! + 1
  • 我的经验是使用字典。我抓住了键并对其进行了迭代,但是当我尝试删除一个元素时它仍然给了我错误,即使我没有迭代集合本身也很困难。我猜 .Keys 属性是一个指向实际字典的指针,所以它会导致同样的错误。制作第二个要删除的键列表就是答案。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    我喜欢使用for 循环向后迭代,但与foreach 相比,这可能会变得乏味。我喜欢的一种解决方案是创建一个向后遍历列表的枚举器。您可以将其作为ArrayListList<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];
            }
        }
    

    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];
            }
        }
    

    下面的示例使用枚举器从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);
        }
    

    【讨论】:

      【解决方案5】:

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

      相反,使用带有索引的for()while(),向后浏览列表。 (这将让您删除内容而不会获得无效的索引。)

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

      【讨论】:

      • 快!那么,我该怎么做呢?
      • 改用常规循环(for/while)。问题在于使用“foreach”语句(即枚举器)。
      • @silky 如果您使用 for() 或 while() 来遍历集合,请务必从后面/顶部进行 - 从 collection.count-1 开始并向下为 0。否则你会遇到同样的问题。
      • 在尝试回答问题时,一个显示要做什么的代码示例是个好主意。
      • @theJerm 并在每个答案上复制和粘贴相同的评论是个坏主意。
      【解决方案6】:

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

      list.RemoveAll(s => s.Name == "Fred");
      

      【讨论】:

        【解决方案7】:

        使用带数字索引的 for() 循环代替 foreach()。

        【讨论】:

        • 如果你使用这种方法,你必须倒数。
        • @Rob - 不是必须,但如果你继续前进,那就更棘手了;有更多方法可以弄错并最终失败。
        • 作为一个正在寻找解决方案的人来说,比仅仅解释更需要一个特定的代码示例。
        • 复制和粘贴不是我想要鼓励的技术。
        【解决方案8】:

        我同意我在这篇文章中读到的一些观点,并将它们纳入我的解决方案中,以解决与原始帖子完全相同的问题。

        也就是说,我欣赏的 cmets 是:

        • “除非您使用 .NET 1.0 或 1.1,否则请使用 List&lt;T&gt; 而不是 ArrayList。”

        • “另外,将要删除的项目添加到新列表中。然后检查并删除这些项目。” ..在我的情况下,我刚刚创建了一个新列表并用有效的数据值填充了它。

        例如

        private List<string> managedLocationIDList = new List<string>();
        string managedLocationIDs = ";1321;1235;;" // user input, should be semicolon seperated list of values
        
        managedLocationIDList.AddRange(managedLocationIDs.Split(new char[] { ';' }));
        List<string> checkLocationIDs = new List<string>();
        
        // Remove any duplicate ID's and cleanup the string holding the list if ID's
        Functions helper = new Functions();
        checkLocationIDs = helper.ParseList(managedLocationIDList);
        
        ...
        public List<string> ParseList(List<string> checkList)
        {
            List<string> verifiedList = new List<string>();
        
            foreach (string listItem in checkList)
            if (!verifiedList.Contains(listItem.Trim()) && listItem != string.Empty)
                verifiedList.Add(listItem.Trim());
        
            verifiedList.Sort();
            return verifiedList;
        }        
        

        【讨论】:

          【解决方案9】:

          使用ArrayList也可以这样尝试

          ArrayList arraylist = ... // myobject data list
          
          ArrayList temp = (ArrayList)arraylist.Clone();
          
          foreach (var item in temp)
          {
                if (...)
                   arraylist.Remove(item);
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-12-07
            • 2012-04-01
            相关资源
            最近更新 更多