为什么我不能在foreach中修改循环变量?

为什么foreach循环是只读循环? 有什么理由呢?

我不确定你的“readonly循环”究竟是什么意思,但我猜你想知道为什么这不能编译:

 int[] ints = { 1, 2, 3 }; foreach (int x in ints) { x = 4; } 

上面的代码将给出以下编译错误:

无法分配给'x',因为它是'foreach迭代变量'

为什么不允许这样做? 试图分配它可能不会做你想要的 – 它不会修改原始集合的内容。 这是因为变量x不是对列表中元素的引用 – 它是一个副本。 为了避免人们编写错误的代码,编译器不允许这样做。

我会假设它是迭代器如何通过列表。

假设您有一个排序列表:

 Alaska Nebraska Ohio 

在中间

 foreach(var s in States) { } 

你做了一个States.Add(“密苏里州”)

你是如何处理的? 如果你已经超过那个指数,你会跳到密苏里州吗?

如果,你的意思是:

为什么我不应该修改那些正在进行的收集?

无法保证您获得的项目按给定顺序出现,添加项目或删除项目不会导致集合中项目的顺序发生变化,甚至无法使枚举器变为无效。

想象一下,如果您运行以下代码:

 var items = GetListOfTOfSomething(); // Returns 10 items int i = 0; foreach(vat item in items) { i++; if (i == 5) { items.Remove(item); } } 

一旦你到达我是6的循环(即在项目被移除后), 任何事情都可能发生 。 由于您删除了一个项目,Enumerator可能已经失效,所有内容可能已经在底层集合中“一个人”,导致项目取代已删除的项目,这意味着您“跳过”一个项目。

如果您的意思是“为什么我不能更改每次迭代提供的值”,那么,如果您正在使用的集合包含值类型 ,那么您所做的任何更改都不会被保留,因为它是您正在使用的值与,而不是参考

foreach命令使用IEnumerable接口循环遍历集合。 接口只定义了单步调试集合并获取当前项的方法,没有更新集合的方法。

由于接口仅定义了在一个方向上读取collecton所需的最小方法,因此接口可以通过各种集合来实现。

由于您一次只能访问一个项目,因此整个集合不必同时存在。 例如,它由LINQ表达式使用,它在您读取时动态创建结果,而不是首先创建整个结果,然后让您循环它。

不确定你的只读是什么意思,但我猜想了解foreach循环在引擎盖下会有什么帮助。 这是语法糖,也可以写成这样的东西:

 IEnumerator enumerator = list.GetEnumerator(); while(enumerator.MoveNext()) { T element = enumerator.Current; //body goes here } 

如果更改集合(列表),很难弄清楚如何处理迭代。 分配给元素(在foreach版本中)可以被视为尝试分配给enumerator.Current,它只读或尝试更改本地的值,将ref保存为枚举器。当然,您可能还要引入一个本地人,因为它不再与枚举列表有任何关系。

foreach适用于实现IEnumerable接口的所有内容。 为了避免同步问题,在迭代时永远不会修改枚举。

如果在迭代时在另一个线程中添加或删除项目,则会出现问题:根据您的位置,您可能会错过某个项目或将您的代码应用于额外的项目。 这是由运行时检测到的(在某些情况下或全部???)并抛出exception:

 System.InvalidOperationException was unhandled Message="Collection was modified; enumeration operation may not execute." 

foreach尝试在每次迭代时获取下一个项目,如果您同时从另一个线程修改它,可能会导致麻烦。