修改IEnumerable foreach与List <T> .ForEach中的结构

roi*_*oim 1 c# ienumerable

这个问题具体是关于结构.

我说定义:

struct Complex
{
    public double real, imaginary;
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试:

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

foreach ( var z in numbers )
{
    z.real += 1;
}
Run Code Online (Sandbox Code Playgroud)

我收到编译错误: 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 );
Run Code Online (Sandbox Code Playgroud)

编译没有错误.记住'foreach'编译错误,有没有理由不在这里给出编译时错误?

Jon*_*eet 7

TL; DR:

  • 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);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 很高兴我没有回答,因为我知道斯基特先生不远了. (2认同)