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

Jim*_*ell 26 c# foreach variable-assignment

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

string[] sArray = new string[5];

foreach (string item in sArray)
{
   item = "Some assignment.\r\n";
}
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*Tao 64

这是你的代码:

foreach (string item in sArray)
{
   item = "Some assignment.\r\n";
}
Run Code Online (Sandbox Code Playgroud)

这是编译器对此做的粗略近似:

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

        // Your code gets put here
    }
}
Run Code Online (Sandbox Code Playgroud)

IEnumerator<T>.Current属性是只读的,但这在实际上并不相关,因为您尝试将局部item变量分配给新值.编译时检查阻止你这样做基本上是为了保护你不要做一些像你期望的那样无法工作的事情(即,更改局部变量并且对底层集合/序列没有影响).

如果要修改索引集合的内部,例如string[]while枚举,传统的方法是使用for循环而不是foreach:

for (int i = 0; i < sArray.Length; ++i)
{
    sArray[i] = "Some assignment.\r\n";
}
Run Code Online (Sandbox Code Playgroud)

  • 很棒的答案!最后一个正确解释正在发生的事情. (2认同)
  • 虽然你是正确的,因为`foreach`只是语法肯定,你在编译器实际上将它转换成什么有点不正确.有关[Eric Lippert博客]上发生的事情的更准确的解释(http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful的.aspx).该帖子讨论了闭包,但它也解释了编译器的作用.其中一个非常重要的区别是临时变量在循环之外被声明为**. (2认同)

Meh*_*ari 6

因为语言规范是这样说的.

但严重的是,并非所有序列都是可以逻辑修改或写入的数组或事物.例如:

foreach (var i in Enumerable.Range(1, 100)) {
   // modification of `i` will not make much sense here.
}
Run Code Online (Sandbox Code Playgroud)

虽然在技术上i = something;修改局部变量在技​​术上是可能的,但它可能会产生误导(你可能认为它确实会改变一些内容并且情况并非如此).

为了支持这些序列,IEnumerable<T>不需要set访问器来获取其Current属性,使其成为只读.因此,foreach无法使用该Current属性修改基础集合(如果存在).


Dom*_*c K 5

foreach循环旨在通过对象集合中迭代,不转让东西-它只是语言的设计.

另外,来自MSDN:

"在只读上下文中对变量赋值时会发生此错误.只读上下文包括foreach迭代变量,使用变量和固定变量.要解决此错误,请避免在使用块,foreach语句中赋值给语句变量和固定的陈述."

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