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; 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);
}

それでもリスト内の値は変更されません...ただし、コンパイル時に失敗することはありません。

于 2013-03-21T17:36:14.557 に答える