1

这个问题专门针对结构。

说我定义:

struct Complex
{
    public double real, imaginary;
}

如果我尝试:

var numbers = new[] 
{
    new Complex() { real = 1, imaginary = 1 },
    new Complex() { real = -1, imaginary = -1 } 
};

foreach ( var z in numbers )
{
    z.real += 1;
}

我得到编译错误:Error: cannot modify members of 'complex' because it is a 'foreach iteration variable'

然而,

var numbers = new List<Complex>();
numbers.Add( new Complex() { real = 1, imaginary = 1 } );
numbers.Add( new Complex() { real = -1, imaginary = -1 } );

numbers.ForEach( z => z.real += 1 );

编译没有错误。牢记“foreach”编译错误,这里有什么理由不给出编译时错误吗?

4

1 回答 1

7

TL;博士:

  • C#试图保护你免受自己的伤害
  • 如果你足够努力,你将能够做坏事——语言并不能保护你免受你可能做的一件愚蠢的事情
  • 可变结构不好

那么有什么理由不在这里给出编译时错误吗?

是的。您只是在修改一个参数,这绝对没问题。参数不被认为是只读的,而循环中的迭代变量foreach认为是只读的。从 C# 5 规范的第 8.8.4 节:

在执行 foreach 语句期间,迭代变量表示当前正在对其执行迭代的集合元素。如果嵌入语句尝试修改迭代变量(通过赋值或 ++ 和 -- 运算符)或将迭代变量作为 ref 或 out 参数传递,则会发生编译时错误。

这并不意味着使用可变变量是一个好主意——这也不意味着你的ForEach循环会做你想做的事。(毕竟参数是按值传递给委托的。)

如果你真的想在版本中做类似的事情(同样无效,但是嘿......)foreach,只需在结构中编写一个改变字段的方法,然后从循环中调用它。这是完全有效的...

// Bad code! Valid, but horrible
foreach (var z in numbers)
{
    z.SetReal(z.real + 1);
}

它仍然不会修改列表中的值......但它不会在编译时失败。

于 2013-03-21T17:36:14.557 回答