对于InvalidOperationException的循环

时间:2014-07-03 06:26:02

标签: c# collections

我经历了许多与使用foreach枚举集合的场景相关的问题,这导致了这个例外:

  

集合被修改枚举操作可能无法执行   例外

大多数情况下,我看到有人建议使用for循环代替foreach循环。

是否有任何特定原因使用for循环来解决问题?或者有没有更好的方法来解决这种情况?

7 个答案:

答案 0 :(得分:1)

当您处理在foreach循环中用完的集合时,不应该执行添加新项目或删除项目等操作,这会修改集合。

但是,当我们按照以下方式进行时,效果很好

List<string> list = new List<string>();

foreach (string str in list.ToList())
{
    list.Remove(str);
}

但是当你这样做时,请注意.ToList()实际上会创建一个新的列表,使其运行良好。每次创建新列表可能不是一个好习惯。

当你实现上面的代码时要明智,或者保持简单,只需使用for循环。

答案 1 :(得分:1)

正如我在评论中发布的那样,您可以使用While来变更集合。这只是为了表明您可以使用变异集合的概念,而不必担心在特定指针处找不到该项。但是你需要自己跟踪项目。

// you will need some sort of indexer
int idx = 0;
while (coll.count > idx)
{

   if (condition met)
   {       
       coll.RemoveAt(idx);
       // you just removed an item, don't up the index
   }
   else
   {
      // Do something with item, for example, or add one more item
      idx += 1;
   }
}

可能效率不高,但这样你就可以使用你的集合变异

答案 2 :(得分:0)

只有在您拥有该集合的活动枚举器时才会出现此情况。 foreach循环使用这样的枚举器。 for循环没有,必须通过使用索引变量来跟踪当前集合中的位置。

没有一般模式可以解决这个问题。就个人而言,如果我发现我的代码正在修改它迭代的集合,我改变了我的逻辑,但也许你的代码更适合for循环方法。

答案 3 :(得分:0)

您将收到此异常,因为在foreach循环中,您尝试修改要枚举的集合。在for循环中,您可以修改集合的元素,但是您需要非常小心,不要进入无限循环情况。

答案 4 :(得分:0)

每个循环的

不保证序列的顺序 在这种情况下,如果您更新每个中的相同集合并尝试再次使用它,您将收到修改集合的错误。

for循环保证了序列的执行顺序。您可以直观地了解在for循环中更新数据所需的实例 关注性能和记忆:

 class Program
{
    static void Main(string[] args)
    {
        string[] test = { "one", "two", "three" }; // your string
        // make a new list of strings to contain all the strings + all the modifications
        List<string> changetest = new List<string>();
        // print out the initial array of strings
        foreach (string s in test)
            Console.WriteLine(s);
        Console.WriteLine();
        // now change the string if it starts with @
        foreach (string s in test)
            if (s.StartsWith("@"))
                changetest.Add(s.Insert(0, "*")); // insert a *
            else
                changetest.Add(s); // else just add
        // print out the modified list of strings
        foreach (string s in changetest)
            Console.WriteLine(s);

        Console.ReadKey();
    }
}

在上面的例子中更新/修改&#39;测试&#39;顺序你需要维护一个更多的集合来接收更新。虽然列表的范围是本地的,元素较少,你可能会遇到一个你将处理巨大/未知集合的情况。

对于每个人本身都说不能修改集合。

如果您想了解更多关于效果的信息,请访问Link

答案 5 :(得分:0)

这几乎是设计上的。您无法按照此MSDN Documentation

中的说明修改在foreach内迭代的集合
  

foreach语句用于遍历集合以获取所需的信息,但不能用于添加或删除源集合中的项目以避免不可预测的副作用。如果需要在源集合中添加或删除项目,请使用for循环。

答案 6 :(得分:0)

当您要从正在迭代的列表中删除项目时,问题是枚举器会丢失您在列表中的位置。

这有点像锯你坐的树枝。你不应该这样做,因为它会有未经检测的行为。

现在,如何解决这个问题?

很容易,你需要复制你的清单,迭代你的副本,并从原始清单中删除这些项目。

听起来很多代码,但你唯一需要做的就是在你的foreach语句中添加ToList()。

示例:

// This will throw an error, because you're modifying the original collection in your foreach statement.
var persons = new List<Persons>();
persons.Add(new Person());
persons.Add(new Person());
persons.Add(new Person());

foreach (var p in persons) {
    persons.remove(p);
}

// This will NOT throw an error, because you're looping over a copy of the pesons list and remove items from the original one.
persons.Add(new Person());
persons.Add(new Person());
persons.Add(new Person());

foreach (var p in persons.ToList()) {
    persons.remove(p);
}

现在,为什么这样做?

这是因为ToList()在内存中创建了列表的副本。所以基本上,你现在正在迭代集合的副本。