35

最初のステートメント:

IEnumerable<char> query = "Not what you might expect";

query = query.Where (c => c != 'a');
query = query.Where (c => c != 'e');
query = query.Where (c => c != 'i');
query = query.Where (c => c != 'o');
query = query.Where (c => c != 'u');

の出力String.Join("", query):"Nt wht y mght xpct"

2 番目のステートメント:

query = "Not what you might expect";

foreach (char vowel in "aeiou")
    query = query.Where (c => c != vowel);

の出力String.Join("", query):"Not what yo might expect"

これらのステートメントからの出力は異なります。誰でも理由を説明できますか?

4

3 に答える 3

57

5.0 より前のバージョンの C# を使用している場合 (これは修正されています)、これが理由です。

クエリのラムダは、ループ変数をキャプチャしますvowel。Linq は遅延実行を使用することを好むため、この参照の値は、ループが終了
した後でクエリが実行されるまで (反復処理によって) 読み取られません。foreachその時点で、 の最新の値はvowelですu。これが、予期しない出力が得られる理由です。

これを回避するには、値を別の一時変数にコピーします (または C# 5.0 にアップグレードします)。

これを試して:

query = "Probably what you might expect";

foreach (char vowel in "aeiou") {
    char currentVowel = vowel;
    query = query.Where (c => c != currentVowel );
}
于 2013-02-27T13:41:34.540 に答える
14

vowelこれは、時間の経過とともに変化する変数に対してクロージャーを作成するためです。その値を別の変数に保存すると、機能します。

query = "Not what you might expect";

foreach (char vowel in "aeiou")
{
    var current = vowel;
    query = query.Where (c => c != current);
}
于 2013-02-27T13:42:57.070 に答える
11

閉鎖についてお読みください。以下を使用する.NET 4.0と、異なる結果が得られます。この.NET 4.5動作で変更 (修正) されます。コンパイラーの展開方法も参照してくださいforeach

于 2013-02-27T13:41:47.210 に答える