【问题标题】:IEnumerables behaving different when deleting Items from them in a For Each loopIEnumerables 在 For Each 循环中从其中删除项目时表现不同
【发布时间】:2016-09-07 21:00:41
【问题描述】:

众所周知,从循环遍历它的 For Each 循环中的 IEnumerable 中删除项目是一个非常糟糕的主意。我一直认为IEnumerable 会在您仍然尝试这样做时抛出异常。
但是我注意到ListTreeNodeCollection 的行为方式不同,尽管它们都实现了IListICollectionIEnumerable

List 的行为符合我的预期。以下代码抛出InvalidOperationException

Dim list As New List(Of String)

list.Add("Entry 1")
list.Add("Entry 2")
list.Add("Entry 3")
list.Add("Entry 4")
list.Add("Entry 5")

For Each entry As String In list
    list.Remove(entry)
Next

TreeNodeCollection 在 .NET 2 中不会引发异常并删除一些项目,在 .NET 4.5.2 中 sn-p 会引发 NullReferenceException

Dim tree As New TreeView
Dim root As TreeNode = tree.Nodes.Add("Root")
root.Nodes.Add("Node 1")
root.Nodes.Add("Node 2")
root.Nodes.Add("Node 3")
root.Nodes.Add("Node 4")
root.Nodes.Add("Node 5")

For Each node As TreeNode In root.Nodes
    root.Nodes.Remove(node)
Next

为什么两个IEnumerables 之间会有如此不同的行为?

【问题讨论】:

  • 我认为你的问题措辞有点奇怪,因为IEnumerable 接口提供了no 修改正在枚举的内容的能力。因此,当您真正对修改感兴趣时,专注于该界面似乎很奇怪。
  • @Damien_The_Unbeliever 我真的不明白为什么这很奇怪。如果你用更好的措辞编辑它,我会很高兴
  • 为什么不只是 Clear()
  • @Paparazzi 因为这些代码应该只展示差异。在我从树中删除节点时遇到问题的应用程序中,我只想删除一些节点,而不是全部
  • 枚举时修改集合是个问题。不要这样做。

标签: .net vb.net exception foreach ienumerable


【解决方案1】:

作为一般规则,如果您想删除项目,您应该先复制:

For Each entry As String In list.ToList()
    list.Remove(entry)
Next

其他选项包括:

  • 使用反向 For 循环。 For i = list.Count-1 To 0 Step - 1
  • 使用 LINQ 创建一个新列表。 list = list.Where(...).ToList

【讨论】:

    【解决方案2】:

    IEnumerable 界面没有任何关于修改的内容,无论是技术上还是通过文档。如果在枚举期间被修改,则没有任何合同要求实现接口的集合抛出异常。

    可能某些集合即使在修改后也完全能够继续枚举。 IE。他们枚举的内容可能是“枚举开始时集合的内容”,或者他们可能对枚举开始后添加或删除的项目提供一些其他保证。

    【讨论】:

      猜你喜欢
      • 2013-10-08
      • 2013-10-15
      • 1970-01-01
      • 2021-05-21
      • 1970-01-01
      • 2021-05-25
      • 1970-01-01
      • 1970-01-01
      • 2012-05-30
      相关资源
      最近更新 更多