【问题标题】:Is it safe to add items to the List while iterating through it在迭代列表时将项目添加到列表中是否安全
【发布时间】:2015-01-09 09:58:37
【问题描述】:

我理解不能同时使用枚举器和修改List<T>。添加或删除项目将使枚举器无效(http://msdn.microsoft.com/en-us/library/system.collections.ienumerator(v=vs.110).aspx),因为内部数组将被重新分配(http://msdn.microsoft.com/en-us/library/3wcytfd1(v=vs.110).aspx)。

  1. 即使Count 小于Capacity,它是否总是正确的?(据我了解,在这种情况下,数组不会被重新分配,因此枚举器必须有效);
  2. 为什么Current 会返回它所设置的元素,即使枚举器已经失效?(我的意思是,如果数组被重新分配...);
  3. 重新分配是否保留了项目的原始顺序?我的意思是,如果某个项目的索引为 n,那么它在添加和项目后是否具有相同的索引?(MSDN 说Add 将一个对象添加到列表的末尾)如果是这样,那么在列表中运行是安全的一个常规的for 循环并添加项目,假设循环将只遍历每个项目一次,对吗?

【问题讨论】:

  • 广告 1. 是 广告 2. 您认为有什么具体原因应该进行额外的处理以防止这种情况发生?广告 3. 是的
  • 问问自己:如果 Current 指向您要删除的项目,迭代器应该移动到上一个还是下一个?如果你在 Current 之后插入一个项目,它是否应该包含在迭代中?以前呢?加到最后应该没问题,但是好像不一致。
  • @decPL 第二点是关于它是如何工作的,而不是为什么它会这样工作。还是谢谢。
  • @MarkO 好吧,我对枚举数为何无效没有疑问,唯一的问题是它何时发生。但是为什么/何时添加到末尾不一致?

标签: c#


【解决方案1】:

即使Count 小于Capacity,它总是正确的

这可能是真的,也可能不是。但是,您应该表现得好像它总是正确的一样,因为文档没有对此行为做出任何例外。

至少one implementation of List<T> (from the Mono project) 总是通过递增一个名为_version 的隐藏成员来使所有迭代器无效,该成员存储在列表中,在每个更改列表的操作中。当您获得一个迭代器(在 .NET 中称为 Enumerator)时,_version 的当前值存储在枚举器对象中。每次调用MoveNext,将存储的_version与当前的_version进行比较,两者不匹配时抛出异常。

为什么Current返回它设置的元素,即使枚举器已经失效?

因为Current 的值存储在迭代器中。虽然有充分的理由阻止您在集合被修改后进一步迭代,但您可以在迭代器有效时访问您将其推进到的位置的值。

重新分配是否保留了项目的原始顺序?

是的。这就是为什么使用 for 循环和索引遍历列表仍然是安全的,即使您在列表中添加或删除元素也是如此。

【讨论】:

    【解决方案2】:
    1. 每次从列表中添加/删除项目时,内部数组都不会重新分配,这不是枚举数无效的原因。这是一个更好的理由:Collection was modified; enumeration operation may not execute - why?

      简单来说,内部数组在容量用完时会重新分配,数组的大小会翻倍。某些集合还允许您修剪内部数组,例如,List<T>.TrimExcess

    2. 为什么不呢?该对象仍然存在。

    3. 是的

    如果您想了解更多信息,请查看source code,尤其是EnsureCapacityList<T>.Enumerator

    【讨论】:

      【解决方案3】:

      添加或删除项目将使枚举器无效,因为 内部数组将被重新分配

      这是部分正确的。添加,删除或插入项目将使枚举器无效不是,因为内部数组将被重新分配,而是因为List<T> 在内部维护一个version 字段以跟踪已发生的更改。 Enumerator 将使用 version 字段来查找自 enumerator 创建以来发生的任何新更新。

      回答您的问题:

      1. 枚举器无效[1] 如果您修改列表而不考虑“计数
      2. 因为枚举器从列表中获取当前元素的副本。
      3. 是的,重新分配会保留订单。

      1:It is not always true,实现有bug。

      【讨论】:

        猜你喜欢
        • 2016-01-03
        • 1970-01-01
        • 2013-03-17
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 2014-07-03
        • 2011-11-16
        相关资源
        最近更新 更多