如何在C#中迭代Collection时添加或删除对象

时间:2013-05-11 12:21:25

标签: c# collections

我正在尝试在迭代Collection时删除对象。但我得到例外。我怎样才能做到这一点? 这是我的代码:

foreach (var gem in gems)
{
    gem.Value.Update(gameTime);

    if (gem.Value.BoundingCircle.Intersects(Player.BoundingRectangle))
    {
       gems.Remove(gem.Key); // I can't do this here, then How can I do?
       OnGemCollected(gem.Value, Player);
    }
}

5 个答案:

答案 0 :(得分:20)

foreach设计用于迭代集合而不修改它。

要在迭代过程中从集合中删除项目,请使用从结尾到开头的for循环。

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);
  }
 }

例如,如果它是dictionary<string, Gem>,您可以像这样迭代:

foreach(string s in gems.Keys.ToList())
{
   if(gems[s].BoundingCircle.Intersects(Player.BoundingRectangle))
   {
     gems.Remove(s);
   }
}

答案 1 :(得分:1)

正如其他答案所说,foreach的设计纯粹是为了迭代集合而不将其修改为per the documenation

  

foreach语句用于遍历集合以获取   所需信息,但不应用于更改内容   该系列旨在避免不可预测的副作用。

为了做到这一点,您需要使用for loop(存储您需要删除的集合的项目),然后将其从集合中删除。

但是,如果您使用List<T>,则可以执行此操作:

lines.RemoveAll(line => line.FullfilsCertainConditions());

答案 2 :(得分:1)

最简单的方式是做@ IV4建议:

foreach (var gem in gems.ToList())

ToList()会将字典转换为KeyValuePair的列表,因此它可以正常工作。

你不想这样做的唯一一次就是如果你有一个大字典,你只需要删除相对较少的项目,并且你想减少内存使用。

只有在这种情况下,您才想使用以下方法之一:


在找到密钥时列出密钥,然后有一个单独的循环来删除项目:

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);

(其中KeyType是您正在使用的密钥类型。替换正确的类型!)

或者,如果在调用OnGemCollected()之前移除很重要,那么(使用键类型TKey和值类型TValue)执行此操作像这样:

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);
}

答案 3 :(得分:0)

您应该使用for循环而不是foreach循环。请参阅here

答案 4 :(得分:0)

集合使用Enumarator支持foreach语句。枚举器可用于读取集合中的数据,但不能用于修改基础集合。如果对集合进行了更改,例如添加,修改或删除元素,则枚举数将无法恢复,并且下一次调用MoveNext或Reset会引发InvalidOperationException。 用于循环以进行集合修改。