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

时间:2010-08-23 16:47:07

标签: 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迭代变量'。”

10 个答案:

答案 0 :(得分:59)

这是你的代码:

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

这是编译器对此做的a rough approximation

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

        // Your code gets put here
    }
}

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

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

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

答案 1 :(得分:5)

foreach循环旨在迭代集合中的对象,而不是分配东西 - 它只是语言的设计。

另外,来自MSDN:

  

“在读取时发生变量赋值时会发生此错误   唯一的背景。只读上下文包括foreach迭代变量,   使用变量和固定变量。要解决此错误,请避免   使用块,foreach中的语句变量赋值   陈述和固定陈述。“

     

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

答案 2 :(得分:5)

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

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

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

虽然技术上可以让i = something;修改一个局部变量,但这可能会产生误导(你可能认为它真的改变了一些东西,但事实并非如此)。

为了支持这类序列,IEnumerable<T>不需要set Current属性的foreach访问器,使其成为只读。因此,Current无法使用{{1}}属性修改基础集合(如果存在)。

答案 3 :(得分:4)

因为您无法使用foreach循环来修改正在循环的数组。循环迭代通过数组,因此如果您尝试修改它迭代的内容,则可能会发生意外行为。此外,正如Darin和DMan指出的那样,你正在迭代IEnumerable,它本身就是只读的。

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

答案 4 :(得分:2)

因为IEnumerable是只读的。

答案 5 :(得分:2)

一般来说,如果你想要这样做,你需要长时间地思考你的设计,因为你可能没有使用最好的结构。在这种情况下,最好的答案可能是

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

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

答案 6 :(得分:1)

您无法修改您正在经历的数组。请改用以下代码:

string[] sArray = new string[5]; 

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

答案 7 :(得分:0)

foreach旨在通过数组进行一次交互,而不重复或跳过(尽管您可以使用continue关键字跳过foreach结构中的某些操作)。 如果要修改当前项,请考虑使用for循环。

答案 8 :(得分:0)

您无法修改通过“ForEach”循环播放的列表。

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

答案 9 :(得分:0)

完全可以改变它。但是,这意味着什么呢?它会读取基础枚举被修改,但它不是(也可以允许它,但它有自己的缺点)。

因此,您可以使用人们自然会阅读的代码,以指示除实际发生的内容之外的其他内容。考虑到计算机语言的目的主要是由人们理解(编译器处理针对它们设置的平衡,除非你使用汇编,机器代码或适当命名的Brainf ** k),这将表明存在一个缺陷。语言。