Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么可以';我不能修改foreach中的循环变量吗?_C#_Foreach - Fatal编程技术网

C# 为什么可以';我不能修改foreach中的循环变量吗?

C# 为什么可以';我不能修改foreach中的循环变量吗?,c#,foreach,C#,Foreach,为什么foreach循环是只读循环?这有什么原因?我不确定您所说的“只读循环”到底是什么意思,但我猜您想知道为什么它不能编译: int[] ints = { 1, 2, 3 }; foreach (int x in ints) { x = 4; } 上述代码将给出以下编译错误: Cannot assign to 'x' because it is a 'foreach iteration variable' 无法分配给“x”,因为它是“foreach迭代变量” 为什么这是不允许的?尝试

为什么
foreach
循环是只读循环?这有什么原因?

我不确定您所说的“只读循环”到底是什么意思,但我猜您想知道为什么它不能编译:

int[] ints = { 1, 2, 3 };
foreach (int x in ints)
{
    x = 4;
}
上述代码将给出以下编译错误:

Cannot assign to 'x' because it is a 'foreach iteration variable' 无法分配给“x”,因为它是“foreach迭代变量”
为什么这是不允许的?尝试分配给它可能不会达到您想要的效果-它不会修改原始集合的内容。这是因为变量x不是对列表中元素的引用-它是一个副本。为了避免人们编写错误代码,编译器不允许这样做

我假设迭代器是如何遍历列表的

假设您有一个排序列表:

Alaska
Nebraska
Ohio
正在

foreach(var s in States)
{
}
你需要一个州。添加(“密苏里州”)

你是怎么处理的?然后,即使你已经通过了密苏里指数,你也会跳到密苏里州吗。

如果,你的意思是:

为什么我不应该修改正在被
foreach
覆盖的集合

无法保证您要获取的项是按给定顺序出来的,并且添加项或删除项不会导致集合中项的顺序更改,甚至不会导致枚举数无效

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

var items = GetListOfTOfSomething(); // Returns 10 items

int i = 0;
foreach(vat item in items)
{
    i++;
    if (i == 5)
    {
        items.Remove(item);
    }
}
一旦你进入我是6的循环(即移除物品后),任何事情都可能发生。枚举数可能因您删除某个项而无效,基础集合中的所有内容都可能“被一次洗牌”,从而导致某个项取代删除的项,这意味着您“跳过”了一个项


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

foreach
适用于实现
IEnumerable
接口的所有内容。为了避免同步问题,在对可枚举项进行迭代时,不得对其进行修改

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

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

foreach
尝试在每次迭代中获取下一项,如果您同时从另一个线程对其进行修改,则可能会导致问题。
foreach
命令使用
IEnumerable
接口在集合中循环。接口仅定义了单步遍历集合并获取当前项的方法,没有更新集合的方法

由于该接口只定义了在一个方向上读取collections所需的最少方法,因此该接口可以由多种集合实现


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

不确定只读的含义,但我猜理解foreach循环的含义会有所帮助。它是语法上的糖分,也可以这样写:

IEnumerator enumerator = list.GetEnumerator();
while(enumerator.MoveNext())
{
   T element = enumerator.Current;
   //body goes here
}
如果更改集合(列表),则很难确定如何处理迭代。
分配给元素(在foreach版本中)可以被视为试图分配给enumerator.Current(只读)或试图更改持有enumerator.Current引用的本地值。在这种情况下,您最好自己引入一个本地,因为它不再与枚举列表有任何关系

我不知道你所说的只读循环是什么意思。您是指不应该修改循环的迭代变量这一事实吗?例如,对于myitems item.property=something nextI中的每个项,我不知道如何将只读概念应用于for循环。或者你是说为什么他们说它是只读的?如果你说的是枚举-是的!你不能改变你正在循环的枚举。是的@Tommy这就是我的意思+1的倍数。这类似于说
foox=newfoo();fooy=x;y=新的Foo()
y
设置为
new Foo()
x
没有任何作用。类似地,将
foo
作为循环变量,并说
foo=newfoo()
(如果可以**)对集合中的
Foo
不做任何操作。对于引用类型,这(复制部分)不是真的,那么x将在IEnumerable@RuneFS:对于引用类型,它是引用的副本。即使在这种情况下,如果您可以分配给它,它也可能不会执行您想要的操作。@Rune,
x
将包含对象的地址。说出
x=newbar()
将创建一个新的
Bar
对象,然后将其地址存储在
x
中。不会修改集合中的对象。这与将参数传递到函数中,然后修改参数没有什么不同。调用站点上的变量不受影响(除非在方法签名中使用了
out
ref
修饰符)。@mark我同意您不分配给“x”,但当您分配给“x”的属性/字段时,无论它是值类型还是引用类型,都会产生很大的差异。在第一种情况下,当循环在第二个循环结束时,更改将丢失,直到再次更改或对象被收集为止。Microsoft的iEnumerable契约表示,iEnumerable不应提供任何更新集合的方法,而不会在枚举下一个元素时引发异常。如果我有我的德鲁瑟斯