枚举一个集合,然后修改它,抛出异常的先例是什么?

发布于 2024-08-16 18:18:27 字数 530 浏览 2 评论 0原文

枚举 .NET 集合时,MSDN 声明 那:

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

“不可恢复地失效”到底是什么意思?

以二叉树为例,其引用向下到左子节点和右子节点,也向上到父节点。在这样的树中,对树中单个节点的单个引用足以在树中导航,因为您可以轻松地从中找到树中的下一个节点。

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

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

When enumerating a .NET collection, MSDN states that:

An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined.

What exactly does "irrecoverably invalidated" mean?

Take a binary tree for instance, with references both down to left and right children, and also up to parent. In such a tree, a single reference to a single node in the tree is enough to navigate through the tree as you can easily find the next node in the tree from it.

So with that tree, suppose I remove some other node (presumably, I don't remove the node I'm currently sitting in), should I still invalidate the enumerator? Note that I'm not talking about multi-threaded operation here, just a single thread running a loop, and modifying the collection inside the loop body.

Is this "law" really that, a law, that even if the enumerator could continue, it shouldn't?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

悍妇囚夫 2024-08-23 18:18:27

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

就我个人而言,我认为让你的枚举器抛出,即使理论上可以继续,也是一个很好的做法。

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

通过总是抛出,您将迫使开发人员将您的代码视为框架的集合和枚举,我认为这是一件好事,因为它减少了处理您的库时的意外程度。

Is this "law" really that, a law, that even if the enumerator could continue, it shouldn't?

Personally, I think that having your enumerator throw, even if it theoretically could continue, is a good practice.

Often, people inadvertently put code that changes a collection inside of a foreach loop. Without doing this, it might not be throwing in the specific instance the developer is currently testing, but a different runtime condition could easily make it throw.

By always throwing, you're forcing the developer to treat your code the same as the framework's collections and enumerations, which I think is a good thing, since it reduces the level of surprise when dealing with your library.

我偏爱纯白色 2024-08-23 18:18:27

标准收集枚举器的实施使其成为一项法律。创建它们时,它会从集合对象中复制一个私有“版本”整数。修改集合会增加该版本。迭代器方法比较版本,当不匹配时会抛出异常。没有办法解决这个问题。

但是,有一个集合类允许在枚举集合时修改集合:Microsoft.VisualBasic.Collection。它需要这样做才能与 VB6 Collection 类保持兼容。您可能想看一下它是如何完成的。 IIRC,它在所有迭代器上保留弱引用,然后在修改集合时更新迭代器。当然,这并不是万无一失的,删除一个元素并将其添加回来可以枚举同一个对象两次。也不便宜。

The implementation of the standard collection enumerators makes it a law. When they are created, it copies a private "version" integer from the collection object. Modifying the collection increments that version. The iterator methods compare the version and when there's a mismatch it throws. No way to get around that.

However, there's one collection class that permits modifying the collection while they are enumerated: Microsoft.VisualBasic.Collection. It needed to do so to stay compatible with the VB6 Collection class. You might want to take a look at it to see how it is done. IIRC, it keeps a WeakReference on all iterators, then update the iterators when the collection is modified. This is not fool proof of course, removing an element and adding it back in can enumerate the same object twice. Nor is it cheap.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文