通常情况下,您不应修改正在循环的集合,而只能修改该集合中的项。在 for each 循环内部删除项的问题在于它会更改正在被循环的集合,并干扰列表计数和迭代位置。
常见解决方案包括:
- 反向循环集合,以便迭代器的干扰不会影响执行
- 创建一个新集合,这样您就可以修改一个集合并循环另一个集合。
反向循环:
这是一个扩展方法,它接受一个 Collection(Of T)
(您可以使用 List(Of T)
,但是列表类已经公开了 RemoveAll
方法,基本上做了相同的事情)。
我们将反向循环并根据传入的 lambda 函数检查集合中每个项的有效性。如果匹配,则将其删除。
<Extension()>
Public Sub RemoveEach(Of T)(ByRef col As Collection(Of T),
ByVal match As Func(Of T, Boolean))
For i = col.Count - 1 To 0 Step -1
If match(col(i)) Then col.RemoveAt(i)
Next
End Sub
然后像这样使用:
Dim col = New Collection(Of Integer)({1, 2, 3, 4}.ToList)
col.RemoveEach(Function(i) (i Mod 2) = 0)
创建新集合:
跟踪集合索引并使用RemoveAt
删除项比使用Remove
更有效,后者需要一个对象,然后检查其余的集合是否与该对象匹配。但是,如果您真的想要一种在For循环中处理删除项的方法,可以在原始集合上调用ToList
,从而创建一个新列表。然后,您可以循环遍历新列表以查找需要从原始列表中删除的项。每当您找到一个对象时,都可以安全地从原始集合中删除它,因为它当前没有被枚举。
<Extension()>
Public Sub RemoveEachObject(Of T)(ByRef col As Collection(Of T),
ByVal match As Func(Of T, Boolean))
For Each o As T In col.ToList()
If match(o) Then col.Remove(o)
Next
End Sub
更多信息,请查看这个很棒的在'foreach'循环中从列表中删除的答案。