C# 为什么赋值运算符(=)在foreach循环中无效?

C# 为什么赋值运算符(=)在foreach循环中无效?,c#,foreach,variable-assignment,C#,Foreach,Variable Assignment,为什么赋值运算符(=)在foreach循环中无效?我使用的是C#,但是我假设对于支持foreach(例如PHP)的其他语言,参数是相同的。例如,如果我这样做: string[] sArray = new string[5]; foreach (string item in sArray) { item = "Some assignment.\r\n"; } 我收到一个错误,“无法分配给'item',因为它是一个'foreach迭代变量'”因为IEnumerable是只读的。因为不能使用

为什么赋值运算符(=)在
foreach
循环中无效?我使用的是C#,但是我假设对于支持
foreach
(例如PHP)的其他语言,参数是相同的。例如,如果我这样做:

string[] sArray = new string[5];

foreach (string item in sArray)
{
   item = "Some assignment.\r\n";
}

我收到一个错误,“无法分配给'item',因为它是一个'foreach迭代变量'”

因为
IEnumerable
是只读的。

因为不能使用
foreach
循环修改正在循环的数组。循环通过数组进行迭代,因此如果您试图修改它所迭代的内容,则可能会发生意外行为。此外,正如Darin和DMan所指出的,您正在迭代一个本身是只读的
IEnumerable


PHP在其
foreach
循环中复制数组,并在该副本中进行迭代,除非您使用引用,在这种情况下,您将修改数组本身。

foreach循环的设计目的是迭代集合中的对象,而不是分配对象-这只是语言的设计

此外,从MSDN:

“在读取过程中发生变量赋值时,会发生此错误- 只读上下文。只读上下文包括foreach迭代变量, 使用变量和固定变量。若要解决此错误,请避免 使用块中语句变量的赋值,foreach 语句和固定语句。”

foreach关键字只是枚举 IEnumerable实例(获取 通过调用 GetEnumerator()方法)。迭代器 是只读的,因此值不能 使用IEnumerator进行更改=无法 使用foreach上下文进行更改


因为语言规范这么说

但说真的,并不是所有的序列都是数组或可以逻辑修改或写入的东西。例如:

foreach (var i in Enumerable.Range(1, 100)) {
   // modification of `i` will not make much sense here.
}
虽然从技术上讲,
i=something修改一个局部变量,它可能会产生误导(你可能认为它确实改变了某些东西,但事实并非如此)


为了支持此类序列,
IEnumerable
不需要为其
当前属性设置
访问器,使其成为只读。因此,
foreach
无法使用
Current
属性修改基础集合(如果存在)。

您无法修改正在进行foreach的数组。请改用以下代码:

string[] sArray = new string[5]; 

for (int i=0;i<sArray.Length;i++)
{
    item[i] = "Some Assignment.\r\n";
}
string[]sArray=新字符串[5];

对于(int i=0;i一般来说,如果你想这样做,你需要仔细考虑你的设计,因为你可能没有使用最好的结构。在这种情况下,最好的答案可能是

string[] sArray = Enumerable.Repeat("Some assignment.\r\n", 5).ToArray();

高级构造几乎总是可用的,而不是C循环中的这种循环(和C++,但这是另一个主题)

这里的代码:

foreach (string item in sArray)
{
   item = "Some assignment.\r\n";
}
以下是编译器如何处理此问题的示例:

using (var enumerator = sArray.GetEnumerator())
{
    string item;
    while (enumerator.MoveNext())
    {
        item = enumerator.Current;

        // Your code gets put here
    }
}
IEnumerator.Current
属性是只读的,但实际上与此无关,因为您正试图将本地
变量分配给一个新值。阻止您这样做的编译时检查基本上是为了保护您不做无法正常工作的事情(即,更改局部变量并且对基础集合/序列没有影响)

如果要在枚举时修改索引集合(如
字符串[]
)的内部结构,传统方法是使用
for
循环,而不是
foreach

for (int i = 0; i < sArray.Length; ++i)
{
    sArray[i] = "Some assignment.\r\n";
}
for(int i=0;i
foreach设计为在数组中交互一次,而不重复或跳过(尽管您可以使用continue关键字跳过foreach构造中的某些操作)。
如果要修改当前项,请考虑使用for循环,

不能通过“Frach”修改正在循环的列表。


最好的选择是简单地创建一个临时列表来存储您想要使用的项目。

完全有可能让它被修改。但是,这意味着什么?它读起来就像底层枚举被修改了一样,但实际上没有(也可以允许这样做,但也有它自己的缺点)


因此,你会有一些代码,人们会自然而然地将其解读为指示实际发生的事情以外的事情。考虑到计算机语言的目的主要是让人们理解(编译器处理与之相对应的平衡,除非你使用汇编、机码或适当命名的Brainf**k)这表明该语言存在缺陷。

我不确定这是否能真正解释“当前项变量”的原因是只读的。@Kirk:因为当前项在读取
IEnumerable
对象时没有被复制。@Kirk Woll,您不能使用
IEnumerator
修改值。
IEnumerator.current
属性是只读的,它没有设置器。@Darin:我没有否决,但Kirk Woll的评论可能是原因的根源为什么。@Darin:我也没有投反对票,但我认为你的答案有误导性,因为你把局部变量和当前属性混为一谈。请看Mehrdad或我的答案来理解我的意思。你可以使用
可枚举性将整件事简化为一条语句。重复一下。答案很好!最后一条是正确的Ry解释了发生了什么。我永远都不会理解他们的编译器:/虽然你在
foreach
只是语法上是正确的,但你在编译器实际将其转换为什么方面有点不正确。这里有一个更准确的解释。这篇文章讨论了闭包,但也解释了compi是的,一个非常重要的