当移除对象时,for循环过早结束

时间:2014-02-27 11:33:26

标签: c# list for-loop

嗨我遇到for循环问题。

看起来像这样

for (int i = 0; i < ObjectManager.Instance.Objects.Count; i++)
{
   if (ObjectManager.Instance.Objects[i] is Asteroid)
   {
      ObjectManager.Instance.Objects.Remove(ObjectManager.Instance.Objects[i]);
   }
}

但是当我删除对象时,计数会变短,导致循环过早结束。有没有办法在没有一堆额外循环的情况下做到这一点。

2 个答案:

答案 0 :(得分:8)

为什么不循环向后

// Just change the order from Count - 1 down to 0 
for (int i = ObjectManager.Instance.Objects.Count - 1; i >= 0; --i)
{
   if (ObjectManager.Instance.Objects[i] is Asteroid)
   {
      ObjectManager.Instance.Objects.Remove(ObjectManager.Instance.Objects[i]);
   }
}

如果您必须循环转发(例如,如果实例应按创建顺序删除,因为它们相互依赖),您可以修改for循环这样:

for (int i = 0; i < ObjectManager.Instance.Objects.Count;)  // <- No increment here
  if (ObjectManager.Instance.Objects[i] is Asteroid)
    ObjectManager.Instance.Objects.Remove(ObjectManager.Instance.Objects[i]);
  else 
    i += 1; // <- Increment should be here!

另一种可能性是 Linq

ObjectManager.Instance.Objects.RemoveAll(item => item is Asteroid);

答案 1 :(得分:4)

三个选项:

  • 如果ObjectManager.Instance.ObjectsList<T>,请将List<T>.RemoveAll与谓词一起使用,使您的代码更多更简单:

    // This replaces your whole loop...
    ObjectManager.Instance.Objects.RemoveAll(x => x is Asteroid);
    
  • 从集合的 end 计算,而不是从开始计算,这样您之后就不需要调整索引了:

    for (int i = ObjectManager.Instance.Objects.Count - 1; i >= 0; i--)
    
  • 调用i后,只需递减Remove,以便在下一次迭代时查看正确的索引。

请注意,在第二个和第三个选项中,如果将表达式ObjectManager.Instance.Objects提取到局部变量中,则在使用它4次之前,您的代码将更容易阅读。另请考虑使用RemoveAt(i)而不是Remove(instances[i]),假设RemoveAt适用于您正在使用的类型。