How add or remove object while iterating Collection in C#

后端 未结 5 1549
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-06 16:52

I am trying to remove object while I am iterating through Collection. But I am getting exception. How can I achieve this? Here is my code :

foreach (var gem          


        
相关标签:
5条回答
  • 2020-12-06 17:12

    foreach is designed for iterating over a collection without modifing it.

    To remove items from a collection while iterating over it use a for loop from the end to the start of it.

    for(int i = gems.Count - 1; i >=0 ; i--)
    {
      gems[i].Value.Update(gameTime);
    
      if (gems[i].Value.BoundingCircle.Intersects(Player.BoundingRectangle))
      {
          Gem gem = gems[i];
          gems.RemoveAt(i); // Assuming it's a List<Gem>
          OnGemCollected(gem.Value, Player);
      }
     }
    

    If it's a dictionary<string, Gem> for example, you could iterate like this:

    foreach(string s in gems.Keys.ToList())
    {
       if(gems[s].BoundingCircle.Intersects(Player.BoundingRectangle))
       {
         gems.Remove(s);
       }
    }
    
    0 讨论(0)
  • 2020-12-06 17:17

    You should use the for loop instead of the foreach loop. Please refer here

    0 讨论(0)
  • 2020-12-06 17:26

    The easiest way is to do what @IV4 suggested:

    foreach (var gem in gems.ToList())
    

    The ToList() will convert the Dictionary to a list of KeyValuePair, so it will work fine.

    The only time you wouldn't want to do it that way is if you have a big dictionary from which you are only removing relatively few items and you want to reduce memory use.

    Only in that case would you want to use one of the following approaches:


    Make a list of the keys as you find them, then have a separate loop to remove the items:

    List<KeyType> keysToRemove = new List<KeyType>();
    
    foreach (var gem in gems)
    {
        gem.Value.Update(gameTime);
    
        if (gem.Value.BoundingCircle.Intersects(Player.BoundingRectangle))
        {
            OnGemCollected(gem.Value, Player);
            keysToRemove.Add(gem.Key);
        }
    }
    
    foreach (var key in keysToRemove)
        gems.Remove(key);
    

    (Where KeyType is the type of key you're using. Substitute the correct type!)

    Alternatively, if it is important that the gem is removed before calling OnGemCollected(), then (with key type TKey and value type TValue) do it like this:

    var itemsToRemove = new List<KeyValuePair<TKey, TValue>>();
    
    foreach (var gem in gems)
    {
        gem.Value.Update(gameTime);
    
        if (gem.Value.BoundingCircle.Intersects(Player.BoundingRectangle))
            itemsToRemove.Add(gem);
    }
    
    foreach (var item in itemsToRemove)
    {
        gems.Remove(item.Key);
        OnGemCollected(item.Value, Player);
    }
    
    0 讨论(0)
  • 2020-12-06 17:29

    As the other answers say, a foreach is designed purely for iterating over a collection without modifying it as per the documenation:

    The foreach statement is used to iterate through the collection to get the desired information, but should not be used to change the contents of the collection to avoid unpredictable side effects.

    in order to do this you would need to use a for loop (storing the items of the collection you need to remove) and remove them from the collection afterwards.

    However if you are using a List<T> you could do this:

    lines.RemoveAll(line => line.FullfilsCertainConditions());
    
    0 讨论(0)
  • 2020-12-06 17:36

    Collections support foreach statement using Enumarator. Enumerators can be used to read the data in the collection, but they cannot be used to modify the underlying collection. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException. Use for loop for collection modifying.

    0 讨论(0)
提交回复
热议问题