【问题标题】:In c# is it safe to expand a List that's being traversed with foreach?在 c# 中扩展一个用 foreach 遍历的 List 是否安全?
【发布时间】:2012-01-11 21:19:59
【问题描述】:

在 c# 中扩展一个使用 foreach 遍历的 List 是否安全?

【问题讨论】:

  • InvalidOperationException: Collection Was Modified
  • 通常最好用函数式编程术语来考虑 - 使用 LINQ 创建新列表(或序列)而不修改旧列表。
  • 您可能应该刚刚尝试过并看到您会收到@VirtualBlackFox 给您的异常...无论如何,有很多方法可以处理您想要执行此操作的场景。也许您需要订阅一些更改事件,也许您需要同步访问,也许队列更有意义......当您添加项目时,您期望会发生什么?您可能仍然可以使用不同的方法来做到这一点......
  • Pete M 在逻辑上似乎是合理的。列表从头到尾被遍历,有时在遍历过程中元素被添加到末尾。
  • 你能发布更多关于你需要做什么的信息吗?我们或许可以为您提供一些替代方案。

标签: c# list collections foreach


【解决方案1】:

我假设扩展是指将新项目添加到集合中。如果是这样,那么答案是否定的,您将在遍历时遇到异常。我不相信任何收藏都能做到这一点。

您可以创建一个新列表,然后在原始列表上执行 AddRange。

【讨论】:

    【解决方案2】:

    在 c# 中扩展一个使用 foreach 遍历的 List 是否安全?如果没有,那么其他收藏呢?

    很少有集合可以安全地让您在迭代时添加它们。这里有很多选择 - 最常见的是从原始集合构建一个新集合,或者在迭代时将项目添加到临时集合中,然后在最后将它们全部添加到原始集合中。

    框架中唯一考虑到迭代和插入的集合是一些并发集合。例如,您可以通过GetConsumingEnumerable 迭代BlockingCollection<T> 并同时向其中添加项目。但是,这是出于不同的目的 - 它通常用于具有单独的消费者和生产者线程,一个添加,而另一个处理项目。因此,在自己的循环中执行此操作将是一个非常奇怪的用例。

    【讨论】:

      【解决方案3】:

      不,你会得到一个例外。虽然不建议这样做,但您可以使用简单的 for 循环来完成您要查找的内容。你得到一个例外的原因是因为 foreach 是如何工作的。编译时,它实际上是使用List<T> 实现的IEnumerable<T>IEnumerable 来获取项目。现在您可以创建自己的收藏集,这将允许这样的事情,但同样不推荐。

      【讨论】:

        【解决方案4】:

        foreach 仅用于查看任何集合的值,如果您要更改集合中元素的数量 - 将引发异常。如果您要更改集合中的值 - 什么都不会发生,但 Microsoft 建议不要在这种情况下使用 foreach。 如果您需要更改元素或元素数量,请使用 list.ToArray() 和 FOR 循环遍历数组。

        【讨论】:

          【解决方案5】:

          只需创建一个新列表。例如按钮:

          List<Button> list = new List<Button>();
          list.Add(new Button());
          list.Add(new Button());
          
          foreach (Button button in new List<Button>(list))
              list.Add(new Button());
          

          不是最好的解决方案,但可能是最简单的。

          【讨论】:

            【解决方案6】:

            这里有些可能很好,有些复杂的解决方案。如何根据列表长度和当前位置在列表中循环一段时间,这应该可以吗?

            UInt16 n = 0;
            while (n < list.Count)
            {
                ... // might add new elements to the end of the list
                n++;
            }
            

            【讨论】:

            • 小心List.Insert(int index, T)
            • 另外请注意,如果有人从列表中删除项目,则会出现竞争条件。如果n == list.Count - 1 并且删除了一个项目,那么尝试访问list[n] 将抛出IndexOutOfRangeExecption
            • 我可以看到有很多这不能做,但它可以很好地用于这个简单的目的,具有我所追求的行为。我认为标准的“foreach”应该更健壮,并且在用作成员函数形式时也更一致。
            猜你喜欢
            • 1970-01-01
            • 2010-09-20
            • 2021-01-02
            • 1970-01-01
            • 1970-01-01
            • 2012-01-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多