16

我在遍历 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);
    }
}
4

5 回答 5

29

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);
   }
}
于 2013-05-11T12:27:06.563 回答
1

正如其他答案所说,foreach 纯粹是为迭代集合而设计的,而无需根据文档对其进行修改:

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

为此,您需要使用for 循环(存储您需要删除的集合的项目),然后将它们从集合中删除。

但是,如果您使用的是 aList<T>您可以这样做:

lines.RemoveAll(line => line.FullfilsCertainConditions());
于 2013-05-11T12:29:52.787 回答
1

简单的方法是执行@IV4 建议的操作:

foreach (var gem in gems.ToList())

ToList()会将 Dictionary 转换为 的列表,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您使用的密钥类型在哪里。替换正确的类型!)

或者,如果在调用之前删除 gem 很重要OnGemCollected(),那么(使用 key typeTKey和 value type 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);
}
于 2013-05-11T12:33:26.143 回答
0

您应该使用 for 循环而不是 foreach 循环。请参考这里

于 2013-05-11T12:25:17.520 回答
0

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

于 2013-05-11T12:33:10.220 回答