【问题标题】:Remove an object when in a for each loop在 for each 循环中删除一个对象
【发布时间】:2013-05-20 00:12:36
【问题描述】:

我正在制作一款生存游戏,并试图在物体离开屏幕时将其移除。代码如下:

Public Sub tmrEnemyMove_Tick(sender As Object, e As EventArgs) Handles tmrEnemyMove.Tick
    Dim koopaAnimation As Boolean

    For Each enemy As enemy In lstEnemy
        enemy.enemy.Left = enemy.enemy.Left - 20

        If enemy.enemy.Tag = "koopa" Then
            enemy.enemy.Image = Image.FromFile(Application.StartupPath + "\Graphics\koopa" + Trim(Str(koopaPosition)) + ".png")
            If koopaAnimation = False Then
                If koopaPosition = 0 Then
                    koopaPosition = 1
                Else
                    koopaPosition = 0
                End If
            End If
            koopaAnimation = True
        End If

        If picMario.Left < enemy.enemy.Left AndAlso enemy.enemy.Left < picMario.Right Or picMario.Left < enemy.enemy.Right AndAlso enemy.enemy.Right < picMario.Right Then
            If picMario.Top < enemy.enemy.Top AndAlso enemy.enemy.Top < picMario.Bottom Or picMario.Top < enemy.enemy.Bottom AndAlso enemy.enemy.Bottom < picMario.Bottom Then
                'MsgBox("Collision")
            End If
        End If

        If enemy.enemy.Left < 0 Then
            lstEnemy.Remove(enemy)
            Me.Controls.Remove(enemy.enemy)
        End If
    Next
End Sub

我得到的错误是: mscorlib.dll 中出现“System.InvalidOperationException”类型的未处理异常 附加信息:集合已修改;枚举操作可能无法执行。

如果有人能提供帮助,那就太好了,谢谢。

【问题讨论】:

  • 在循环遍历集合时,您不能像这样更改集合,如果您考虑一下,原因很明显。在循环中获取对对象的引用,然后删除

标签: vb.net loops object foreach


【解决方案1】:

您不能在枚举期间从集合中删除对象。您根本无法修改集合。这将导致错误(集合已修改;枚举操作可能无法执行)。但是您可以将要删除/移除的对象添加到另一个集合中:

Dim removeEnemies = New List(Of enemy)
For Each enemy As enemy In lstEnemy
    ' ... '
    If enemy.enemy.Left < 0 Then
        removeEnemies.Add(enemy.enemy)
    End If
Next

For Each enemy In removeEnemies
    lstEnemy.Remove(enemy)
    Me.Controls.Remove(enemy.enemy)
Next

以下所有方法都会导致列表更改其版本(在枚举期间检查):

  • 添加
  • 清除
  • 插入
  • 插入范围
  • 移除
  • 移除范围
  • 删除时间
  • 反向
  • [索引器设置器]
  • 排序

另一种选择是使用For-Loop 并向后循环:

 For i As Int32 = lstEnemy.Count - 1 To 0 Step -1
    Dim enemy = lstEnemy(i)
    ' ... '
    If enemy.enemy.Left < 0 Then
        lstEnemy.Remove(enemy)
        Me.Controls.Remove(enemy.enemy)
    End If
Next

这不会引发该错误,但它的可读性不高。您需要从list.Count - 1 转到0,因为您要删除会更改Count 属性的项目,并且在删除该项目之前可用的索引现在导致ArgumentOutOfRangeException

最后但同样重要的是,您可以使用List.RemoveAll

lstEnemy.RemoveAll(Function(enemy) enemy.enemy.Left < 0)

【讨论】:

  • 其他选项是使用一段时间。很好的答案
【解决方案2】:

.NET 真的不喜欢在枚举其内容的过程中更改集合。如果您打算像这样从集合中删除元素,您可以尝试将 foreach 循环更改为 for 循环。

【讨论】:

    【解决方案3】:

    使用实体框架(ElementAt(i))的一个例子:

    for (int i = 0; i < db.Itens.Count(); i++)
    {
        Item item = db.Itens.ElementAt(i);
        if (item.Id == 0) // put a condition
        {
            db.Itens.Remove(item);
            i--;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-12
      • 1970-01-01
      • 2013-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多