【问题标题】:"Collection was modified..." Issue“收藏已修改...”问题
【发布时间】:2010-05-25 03:13:00
【问题描述】:

我有一个函数可以检查对象列表以查看它们是否已被单击并相应地触发 OnClick 事件。我相信该功能可以正常工作,但是我遇到了问题:

当我连接到其中一个 OnClick 事件并将元素删除并插入到列表中的不同位置(此程序的典型功能)时,我收到“集合已修改...”错误。

我相信我明白发生了什么:

  • 该函数循环遍历每个在必要时触发 OnClick 事件的对象
  • 一个事件被触发,并且对象根据挂钩函数更改列表中的位置
  • 迭代时修改集合引发异常

我的问题是,如何让函数遍历所有对象,在适当的时间触发必要的事件,并且仍然让用户可以选择操作对象在列表中的位置?

【问题讨论】:

    标签: c# collections exception


    【解决方案1】:

    此类问题有两种通用解决方案:

    • 制作列表的副本。迭代副本。
    • 列出需要进行的更改。完成迭代后应用更改。

    如果您想将进行更改的代码与执行循环的代码分离,“使用索引”选项听起来并不合适。

    【讨论】:

    • 我认为第二个选项听起来最好。我将在更新期间记录对列表的任何修改,然后在迭代完成后应用它们。
    • 请注意,当您进行多次编辑时,您必须清楚“位置”的确切含义——“交换 1 和 2”和“交换 2 和 3”,或“移动” A 之后的 C”和“删除 A”。我通常发现通过迭代副本更容易编写正确的代码,即使它可能非常低效。
    【解决方案2】:
    • 使用集合的副本而不是初始集合进行迭代。

    • 如果您有一个支持索引的集合(如 List),您可以使用“for”循环而不是使用“foreach”进行迭代。

    【讨论】:

      【解决方案3】:

      如果您使用 foreach 循环来操作集合,请尝试将其替换为

      for (int a = items_count - 1; a >= 0; --a)
      

      【讨论】:

      • 只有当您可以通过索引直接访问集合项时才可以这样做。
      【解决方案4】:

      你看到的行为是by design

      C#的foreach语句 语言(适用于 Visual Basic 中的每种语言) 隐藏了复杂性 枚举器。因此,使用 foreach 建议而不是直接 操作枚举器。

      枚举器可用于读取 集合中的数据,但它们 不能用于修改 基础集合。

      触发一个同步执行的事件与在foreach 循环中修改集合的效果相同。

      我的偏好是向后使用 for 循环,这样可以避免根据您是否插入内容来更新循环索引的条件逻辑:

      for (var i = collection.Count - 1; i >= 0; i--) {
        if (condition)
          collection.Insert(i, item);
      }
      

      相应的递增循环如下所示:

      for (var i = 0; i < collection.Count; i++) {
        if (condition) {
          collection.Insert(i, item);
          i++;
        }
      }
      

      【讨论】:

        【解决方案5】:

        在迭代时不能修改集合。您需要先标记要从集合中移除的项目,然后再移除它们。您可以根据您的要求在删除项目之前或之后触发事件。这段代码 sn-p 显示了我所涉及的内容

        List itemsTobeRemoved=new List(); for (var i = 0; i

        foreach (var i = 0 in itemsTobeRemoved) { 如果(条件){ 集合.RemoveAt(i); }

        【讨论】:

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