如何在C#中迭代Collection时添加或删除对象
我在迭代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); } }
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 OnGemCollected(gem.Value, Player); } }
例如,如果它是dictionary
,您可以像这样迭代:
foreach(string s in gems.Keys.ToList()) { if(gems[s].BoundingCircle.Intersects(Player.BoundingRectangle)) { gems.Remove(s); } }
正如其他答案所说,foreach被设计为纯粹用于迭代集合而不根据文档修改它:
foreach语句用于迭代集合以获取所需信息,但不应用于更改集合的内容以避免不可预测的副作用。
为了做到这一点,你需要使用for循环 (存储你需要删除的集合的项目),然后从集合中删除它们。
但是,如果您使用List
,则可以执行以下操作:
lines.RemoveAll(line => line.FullfilsCertainConditions());
最简单的方法是做@ IV4建议的事情:
foreach (var gem in gems.ToList())
ToList()
会将Dictionary转换为KeyValuePair
列表,因此它可以正常工作。
你不想这样做的唯一一次是你有一个大字典,你只需要删除相对较少的项目,并且你想减少内存使用。
只有在这种情况下,您才想使用以下方法之一:
在找到密钥时列出密钥,然后有一个单独的循环来删除项目:
List keysToRemove = new List (); 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()
之前删除gem很重要,那么(使用键类型TKey
和值类型TValue
)执行如下操作:
var itemsToRemove = new List>(); 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); }
您应该使用for循环而不是foreach循环。 请参考这里
集合使用Enumarator支持foreach语句。 枚举器可用于读取集合中的数据,但不能用于修改基础集合。 如果对集合进行了更改,例如添加,修改或删除元素,则枚举数将无法恢复,并且下一次调用MoveNext或Reset会引发InvalidOperationException。 用于循环以进行集合修改。