Vb.net 从列表中删除项会导致System.InvalidOperationException

Vb.net 从列表中删除项会导致System.InvalidOperationException,vb.net,list,collections,foreach,Vb.net,List,Collections,Foreach,这种情况经常发生在我身上,如果满足某个条件,我需要从列表中删除项目 我更喜欢这样做: For Each nClass As SomeClass In MyList If (Something) Then MyList.Remove(nClass) End If Next 但是,当我删除一个项时,集合被更改,For Next语句无法继续,并引发System.InvalidOperationException 我想知道是否有任何通用的方法可以在不编写大的变通方法的

这种情况经常发生在我身上,如果满足某个条件,我需要从列表中删除项目

我更喜欢这样做:

For Each nClass As SomeClass In MyList
    If (Something) Then
        MyList.Remove(nClass)
    End If
Next 
但是,当我删除一个项时,集合被更改,For Next语句无法继续,并引发System.InvalidOperationException

我想知道是否有任何通用的方法可以在不编写大的变通方法的情况下正确地完成这项工作

有谁能告诉我们应该如何正确地做到这一点

我正在附加测试代码以查看错误:

Public Class Form1

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    Dim nList As New List(Of SomeClass)

    For i As Integer = 0 To 5
        Dim nNewItem As New SomeClass
        nNewItem.Int = i
        nNewItem.Text = "My text " + i.ToString
        nList.Add(nNewItem)
    Next

    For Each nItem As SomeClass In nList
        If nItem.Int > 1 And nItem.Int < 5 Then
            nList.Remove(nItem)
        End If
    Next

End Sub

End Class

Public Class SomeClass
Private _iInt As Integer = 0
Private _sText As String = String.Empty

Public Property Int() As Integer
    Get
        Return _iInt
    End Get
    Set(value As Integer)
        _iInt = value
    End Set
End Property

Public Property Text() As String
    Get
        Return _sText
    End Get
    Set(value As String)
        _sText = value
    End Set
End Property
End Class
公共类表单1
私有子表单1_Load(发送方作为对象,e作为事件参数)处理MyBase.Load
Dim nList作为新列表(SomeClass的)
对于i,整数=0到5
作为一个新的职业
nNewItem.Int=i
nNewItem.Text=“我的文本”+i.ToString
nList.Add(nNewItem)
下一个
将每个nItem作为nList中的某个类
如果nItem.Int>1且nItem.Int<5,则
nList.Remove(nItem)
如果结束
下一个
端接头
末级
公共类
Private _iInt作为整数=0
Private _stextas String=String.Empty
公共属性Int()为整数
得到
返回
结束
设置(值为整数)
_iInt=值
端集
端属性
公共属性Text()作为字符串
得到
返回_sText
结束
设置(值为字符串)
_sText=值
端集
端属性
末级

正如Puropoix所说,您需要通过循环反向工作-

改变

For Each nItem As SomeClass In nList
    If nItem.Int > 1 And nItem.Int < 5 Then
        nList.Remove(nItem)
    End If
Next
将每个nItem作为nList中的某个类
如果nItem.Int>1且nItem.Int<5,则
nList.Remove(nItem)
如果结束
下一个

对于I As Integer=nList.Count到0步骤-1
如果nlist(I).Int>1且nlist(I).Int<5,则
nList.RemoveAt(一)
如果结束
下一个
原因是在一个
For Each..Next
循环中,对象中的项数记录在循环的开始处,并且不会改变。即使在对象中添加或删除项目

比如说。假设你从10个字母的列表开始

A

B

C

D

E

F

G

H

J

所以。在每个循环的
开始时,记录项目数(10)。当循环遍历列表时,假设您删除了“E”

为了这个解释的目的,哪一个并不重要。无论如何,最终所有后续项目都将向后移动一个。所以在指数第5位的东西将在第4位,依此类推,在指数第10位的东西现在在指数第9位。循环继续进行,当它试图访问索引10处的项时,它不存在,因为它超出了现在有9个项的列表的界限


相反,如果您使用“For..Next”循环,并从列表项开始向后移动,当您说“E”并想要删除它时,然后一次又一次地向后移动,直到到达第一项,第一项仍然位于相同的索引位置,所以没问题。

您是否尝试克隆MyList并循环克隆,从MyList中删除?如果是,请从列表中的最后一项循环到第一项,例如
对于x As Integer=MyList.Count-1到0步骤-1
在这种情况下,您必须向后循环的可能重复项,一旦集合被修改,枚举器就会失效。但是,为什么枚举器会因为它已经处理了一个项而变为berzek?我不明白为什么在使用RemoveAt时必须反向工作。在您的代码中,循环第一次启动时,项数由程序内部存储。如果删除项目,则程序存储的原始计数不会更新。因此,如果您有一个包含10项的列表,那么您的
For Each
循环将存储10项,并将循环多次。但是,如果您从该循环的列表中删除一个项目,那么项目的数量将是9,但是您的
For..Each
循环仍会认为有10个项目需要处理,并且当它尝试处理第10个项目时,它将不存在。您必须反向工作,因为如果您从项目10开始,并说您删除了项目9,循环中的下一项是第9项、第8项,依此类推到0。任何时候都不会有不存在的项目。希望一切都有帮助
For I As Integer = nList.Count to 0 Step -1
    If nlist(I).Int > 1 And nList(I).Int < 5 Then
        nList.RemoveAt(I)
    End If
Next