我经历了许多与使用foreach
枚举集合的场景相关的问题,这导致了这个例外:
集合被修改枚举操作可能无法执行 例外
大多数情况下,我看到有人建议使用for
循环代替foreach
循环。
是否有任何特定原因使用for
循环来解决问题?或者有没有更好的方法来解决这种情况?
答案 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()在内存中创建了列表的副本。所以基本上,你现在正在迭代集合的副本。