Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove an object when in a for each loop

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.

If anyone could help that would be great, thanks.

like image 466
Tyler Hilbert Avatar asked May 24 '13 11:05

Tyler Hilbert


People also ask

Can you remove elements in a for each loop?

The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove . Therefore, the for-each loop is not usable for filtering.

How do you remove something from a list while iterating?

If you want to delete elements from a list while iterating, use a while-loop so you can alter the current index and end index after each deletion.

How do you remove an element from a generic list while iterating over it?

The best way to remove items from a list while iterating over it is to use RemoveAll() .


1 Answers

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-Loop and loop it backwards:

 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 - 1 To 0 because you want to remove items which would change the Count property and an index that was available before the item was removed causes now an ArgumentOutOfRangeException.

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

lstEnemy.RemoveAll(Function(enemy) enemy.enemy.Left < 0)
like image 182
Tim Schmelter Avatar answered Sep 29 '22 13:09

Tim Schmelter