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 编译器版本 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# 版本中,它只定义一次。

有关详细信息,请参阅 Eric Lippert 的精彩博文

更值得注意的是,开头段落:

更新:我们正在进行重大更改。在 C# 5 中,foreach 的循环变量在逻辑上将位于循环内部,因此闭包每次都会关闭变量的新副本。“for”循环不会改变。我们现在将您返回到我们的原始文章。

于 2013-09-05T15:11:49.850 回答