8

C# 3.5 および 4.0 で次のコードを実行しました。結果はまったく異なります。

    static void Main()
    {       
        int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        List<IEnumerable<int>> results = new List<IEnumerable<int>>();

        foreach (var num in numbers)
        {
            results.Add(numbers.Where(item => item > num));
        }

        foreach (var r in results)
        {
            Console.WriteLine("{0}", r.Count());
        }        
    }

Microsoft (R) Visual C# 2008 Compiler バージョン 3.5.30729.5420 では、出力は0 0 0 0 0 0 0 0 0 0.

しかし、Microsoft (R) Visual C# Compiler バージョン 4.0.30319.17929 では、出力は9 8 7 6 5 4 3 2 1 0.

これは遅延実行または遅延評価が原因であるというかすかな考えがありますが、ここでさまざまな出力にどのように責任があるかを明確に理解していません。

訂正: .NET 3.5 および 4.5 であり、コンパイラのバージョンも追加されまし た。説明してください。

4

2 に答える 2

7

c# 5 以降、ループ変数 inforeachは、ループ スコープの外側ではなくループ スコープ内に存在するようにコンパイルされます。

これは、ループ変数を閉じると、異なる結果が得られることを意味します。

元の問題についてEric Lippert が言わなければならなかったことは次のとおりです。

于 2013-09-05T15:10:06.130 に答える
6

クロージャ内の変数にアクセスしたため、コンパイラのバージョンによって結果が異なります。

C# 5.0 では、変数はループの反復ごとに再定義されますが、以前の C# バージョンでは 1 回しか定義されていませんでした。

詳細については、Eric Lippert の素晴らしいブログ投稿を参照してください。

さらに注目すべきは、冒頭の段落です。

更新: 互換性を破る変更を行っています。C# 5 では、foreach のループ変数は論理的にループ内にあるため、クロージャーは毎回変数の新しいコピーを閉じます。「for」ループは変更されません。元の記事に戻ります。

于 2013-09-05T15:11:49.850 に答える