[解決済み] C#がforeachで変数を再利用するのは理由があるのか?
質問内容
C#でラムダ式や匿名メソッドを使用する際、注意しなければならないのが 変更されたクロージャへのアクセス の落とし穴です。例えば
foreach (var s in strings)
{
query = query.Where(i => i.Prop == s); // access to modified closure
...
}
クロージャが変更されたため、上記のコードでは、すべての
Where
の最終的な値に基づいています。
s
.
説明したように
これ
があるため、このようなことが起こります。
s
で宣言された変数は
foreach
のループは、コンパイラで次のように翻訳されます。
string s;
while (enumerator.MoveNext())
{
s = enumerator.Current;
...
}
ではなく、このように
while (enumerator.MoveNext())
{
string s;
s = enumerator.Current;
...
}
ご指摘の通り これ ループの外側で変数を宣言することにパフォーマンス上の利点はありませんし、通常であれば、ループの範囲外で変数を使用する予定がある場合のみ、宣言する理由が考えられます。
string s;
while (enumerator.MoveNext())
{
s = enumerator.Current;
...
}
var finalString = s;
ただし
foreach
ループの外側で使用することはできません。
foreach(string s in strings)
{
}
var finalString = s; // won't work: you're outside the scope.
そのため、コンパイラはこの変数を、発見とデバッグが困難なエラーが発生しやすい方法で宣言し、その一方で、目に見える利点は何も生み出さないのです。
でできることはないのでしょうか?
foreach
それとも、匿名メソッドやラムダ式が一般的になる前に作られた恣意的な選択で、それ以降も変更されていないのでしょうか?
どのように解決するのですか?
<ブロッククオートコンパイラは、発見とデバッグが困難なエラーが発生しやすい方法で変数を宣言していますが、目に見える利点はありません。
あなたの批判はまったく正当なものです。
この問題については、こちらで詳しく説明しています。
foreachループをインナースコープ変数でコンパイルした場合にはできないことが、この方法ではできるのでしょうか?それとも、匿名メソッドやラムダ式が一般的になる前に行われ、その後も改訂されていない、単なる恣意的な選択なのでしょうか?
後者です。C# 1.0仕様では、ループ変数がループ本体の内側にあるか外側にあるかは、観察可能な違いがないため、実は明言されていませんでした。C# 2.0でクロージャーのセマンティクスが導入されたとき、ループ変数をループの外側に置くという選択がなされ、"for"ループと一致するようになったのです。
その判断は、誰もが後悔していると言っていいと思います。これは、C#における最悪のゴッチャの1つであり、また 私たちは、それを修正するために、ブレークチェンジを行うつもりです。 C# 5では、foreachループの変数は、論理的に 内側 そのため、クロージャは毎回新しいコピーを取得します。
は
for
ループは変更されず、その変更は以前のバージョンの C# に "バックポート" されません。したがって、このイディオムを使用する場合は、引き続き注意が必要です。
関連
-
[解決済み】「The breakpoint will not currently be hit」を改善するには?このドキュメントにはシンボルが読み込まれていません。" という警告はどうすれば改善されますか?
-
[解決済み】C#で四捨五入する方法
-
[解決済み】Linq 構文 - 複数列の選択
-
[解決済み] C#の正しいバージョン番号を教えてください。
-
[解決済み] Javaの「for each」ループはどのように機能するのですか?
-
[解決済み] foreachループの現在の反復処理のインデックスを取得するにはどうすればよいですか?
-
[解決済み] IEnumerable<T>のforeachのLINQでの等価性
-
[解決済み] Goにforeachループはあるのか?
-
[解決済み] foreach インデックスを見つけるには?
-
[解決済み】Pythonのforループのスコープについて
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] [Solved] 1つ以上のエンティティで検証に失敗しました。詳細は'EntityValidationErrors'プロパティを参照してください [重複]。
-
[解決済み] [Entity Framework 4.1でエンティティに関連オブジェクトを追加する際に、エンティティオブジェクトをIEntityChangeTracker.の複数のインスタンスから参照できない。
-
[解決済み】Excel "外部テーブルが期待された形式ではありません。"
-
解決済み] Critical error detected c0000374 - C++ dll returns pointer off allocated memory to C# [解決済み] Critical error detected c0000374 - C++ dll returns pointer off allocated memory to C#.
-
[解決済み] [Solved] アセンブリ System.Web.Extensions dll はどこにありますか?
-
[解決済み】ファイルへの読み書きの際に共有違反のIOExceptionが発生する C#
-
[解決済み】WSACancelBlockingCallの例外について
-
[解決済み】エラー「必要なフォーマルパラメータに対応する引数が与えられていない」を解決する?
-
[解決済み】URLから画像をダウンロードする方法
-
[解決済み】スレッド終了またはアプリケーションの要求により、I/O操作が中断されました。