vb.net 在 for each 循环中删除对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16734186/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Remove an object when in a for each loop
提问by Tyler H
I'm making a survival game and trying to remove an object when it goes off the screen. Here is the code:
我正在制作一个生存游戏并试图在它离开屏幕时移除一个物体。这是代码:
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
The error I get is: An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll Additional information: Collection was modified; enumeration operation may not execute.
我得到的错误是: mscorlib.dll 中发生类型为“System.InvalidOperationException”的未处理异常附加信息:集合已修改;枚举操作可能无法执行。
If anyone could help that would be great, thanks.
如果有人可以提供帮助,那就太好了,谢谢。
回答by Tim Schmelter
You cannot delete an object from a collection during enumeration. You cannot modify the collection at all. That will cause an error (Collection was modified; enumeration operation may not execute). But you could add the objects that you want to delete/remove to another collection:
您不能在枚举期间从集合中删除对象。您根本无法修改集合。这将导致错误(集合已修改;枚举操作可能无法执行)。但是您可以将要删除/移除的对象添加到另一个集合中:
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
All of the following methods will cause a list to change its version (which is checked during enumeration):
以下所有方法都会导致列表更改其版本(在枚举期间检查):
- Add
- Clear
- Insert
- InsertRange
- Remove
- RemoveRange
- RemoveAt
- Reverse
- [the Indexer setter]
- Sort
- 添加
- 清除
- 插入
- 插入范围
- 消除
- 删除范围
- 删除在
- 逆转
- [索引器设置器]
- 种类
Another option is to use a For-Loopand loop it backwards:
另一种选择是使用 aFor-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
This will not raise that error but it's not as readable. You need to go from list.Count - 1To 0because you want to remove items which would change the Countproperty and an index that was available before the item was removed causes now an ArgumentOutOfRangeException.
这不会引发该错误,但它的可读性较差。您需要从list.Count - 1To 开始,0因为您想要删除会更改Count属性的项目,并且在删除项目之前可用的索引现在会导致ArgumentOutOfRangeException.
Last but not least, you can use List.RemoveAll:
最后但并非最不重要的是,您可以使用 List.RemoveAll:
lstEnemy.RemoveAll(Function(enemy) enemy.enemy.Left < 0)
回答by Adrian
.NET really doesn't like it when you change a collection when you're in the middle of enumerating its contents. You might try chAnging your foreachloop to a forloop if you're planning on removing elements from the collection like this.
当您在枚举其内容的过程中更改集合时,.NET 真的不喜欢它。如果您打算像这样从集合中删除元素,则可以尝试将foreach循环更改为for循环。
回答by Fernando Mota
One example using entity framework (ElementAt(i)):
使用实体框架 (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--;
}
}

