代码之家  ›  专栏  ›  技术社区  ›  Lasse V. Karlsen

枚举集合,然后修改它,引发异常的先例是什么?

  •  2
  • Lasse V. Karlsen  · 技术社区  · 15 年前

    枚举.NET集合时, MSDN states 那就是:

    只要集合保持不变,枚举器就保持有效。如果对集合进行了更改,例如添加、修改或删除元素,则枚举器将不可恢复地失效,并且其行为未定义。

    “不可恢复的无效”究竟是什么意思?

    以二叉树为例,它的引用既有从左到右的子级,也有从上到父级。在这样的树中,对树中单个节点的单个引用足以在树中导航,因为您可以很容易地从树中找到下一个节点。

    因此,对于该树,假设我删除了一些其他节点(假设我没有删除当前所在的节点),我应该仍然使枚举器失效吗?注意,这里我不是在讨论多线程操作,只是一个运行循环的线程,并修改循环体中的集合。

    这条“法律”真的是这样吗,一条法律,即使列举者 能够 继续,不应该?

    2 回复  |  直到 11 年前
        1
  •  8
  •   Reed Copsey    15 年前

    这条“法律”真的是这样吗,一条法律,即使枚举器可以继续,它也不应该继续?

    我个人认为,让你的枚举器抛出,即使理论上可以继续,也是一个好的实践。

    通常,人们会无意中将更改集合的代码放入foreach循环中。如果不这样做,它可能不会在开发人员当前正在测试的特定实例中引发,但是不同的运行时条件很容易使它引发。

    通过总是抛出代码,您迫使开发人员将代码视为框架的集合和枚举,我认为这是一件好事,因为它可以降低处理库时的意外级别。

        2
  •  2
  •   Hans Passant    15 年前

    标准集合枚举器的实现使其成为一项法律。创建它们时,它会从集合对象复制一个私有的“版本”整数。修改集合会增加该版本。迭代器方法比较版本,如果不匹配,它就会抛出。没办法避开那个。

    但是,有一个集合类允许在枚举集合时修改集合:microsoft.visualBasic.collection。需要这样做才能与vb6集合类保持兼容。你可能想看看它是怎么做到的。IIRC,它在所有迭代器上保持weakreference,然后在修改集合时更新迭代器。当然,这不是简单的证明,删除一个元素并将其添加回可以枚举同一个对象两次。它也不便宜。