Remove the object when in for each cycle

I do survival and try to delete an object when it leaves 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: An unhandled exception of type "System.InvalidOperationException" occurred in mscorlib.dll Additional information: the collection has been modified; enumeration operation cannot be performed.

If someone can help, that would be great, thanks.

+6
source share
3 answers

You cannot remove an object from the collection during enumeration. You cannot modify the collection at all. This will cause an error (the collection has been modified, the enumeration operation may not be performed). But you can add the objects you want to delete / delete in 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 

These methods will force the list to change its version (which is checked during enumeration):

  • Add
  • Clear
  • Embed
  • Insertrange
  • Delete
  • Removerange
  • Removeat
  • Reverse
  • [indexer installer]
  • Sorting

Another option is to use For-Loop and loop it back:

  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 result in this error, but is not readable like that. You need to go from list.Count - 1 To 0 , because you want to remove items that would have changed the Count property, and the index that was available before the item was deleted now raises an ArgumentOutOfRangeException .

Last but not least, you can use List.RemoveAll :

 lstEnemy.RemoveAll(Function(enemy) enemy.enemy.Left < 0) 
+13
source

.NET really doesn’t like it when you change a collection when you are in the middle of listing its contents. You can try to execute the foreach in a for loop if you plan to remove items from the collection like this.

+1
source

One example using the framework (ElementAt (i)) entity:

 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--; } } 
0
source

Source: https://habr.com/ru/post/945773/


All Articles