我有一个通用列表,我正在删除使用List.Remove(Object)
的项目。我一直在删除项目,但每当我到达第五项我删除它失败,并没有从列表中删除它。我删除的内容似乎并不重要,但每次我尝试删除第五项时失败的五个项目。
可能导致这种情况的原因是什么?查看List(Of T).Remove
的文档,它没有指定他们用于删除项目的算法。
答案 0 :(得分:12)
Remove
将根据您对象上的.Equals
进行匹配。默认情况下,对于给定对象,它只匹配相同的对象。如果你想要两个具有相同属性的对象被认为是相等的,即使它们不是同一个对象,你需要覆盖Equals
方法并将你的逻辑放在那里。
然而,另一个好的选择是使用RemoveAll
并传入一个匿名委托或一个lambda表达式,其中包含您正在寻找的标准。 E.g:
customers.RemoveAll(customer => customer.LastName.Equals(myCustomer.LastName));
当然,只有当您真的要删除所有匹配的项目时才会有效,并且/或者如果您确定只有匹配的项目会匹配。
答案 1 :(得分:2)
如果您正在使用基于索引的方法从列表中删除项目,请记住,删除项目之后的项目索引将在您删除之前更改为-1。
答案 2 :(得分:0)
列表中有多少项?你如何删除它们,只是循环?请记住,这些是基于0的列表。如果您正在使用整数进行任何类型的For循环,则可能无法正常删除项目。
答案 3 :(得分:0)
作为一般规则,您不应修改正在循环的集合,只应修改该集合中的项目。删除每个循环中的项目的问题是它会更改正在循环的集合并干扰列表计数和迭代位置。
这是一个接受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)
'Produces list of 1 & 3
跟踪集合索引并使用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
有关详细信息,请查看这篇精彩的answer to Remove from a List within a 'foreach' loop。
答案 4 :(得分:-1)
如果你使用for循环来删除元素,你应该考虑使用foreach,它更适合于集合,列表和可数对象