Difference in LINQ query results in .NET 3.5 and 4.5
我用C 3.5和4.0执行了以下代码。结果完全不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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编译器4.0.30319.17929版,输出是9 8 7 6 5 4 3 2 1 0。
我有一个模糊的想法,这是因为延迟的执行或延迟的评估,但我不清楚它是如何对这里的不同输出负责的。
更正:抱歉,它是.NET 3.5和4.5版本,还添加了编译器版本请解释一下。
- 我在3.5和4.0中得到相同的输出,9 8 7…}你确定你没有做什么不同的事情吗?
- 它给了我同样的结果……
- 我相信这一变化发生在4.5,而不是4.0。
- @Joeenos它与.NET版本无关,它与正在使用的C版本相关。
- @谢谢,谢谢。有时很难把这些区别弄清楚。
- @Joeenos我在.NET版本上犯了一个错误,但在这个问题上我提到了编译器的版本。
- @谢谢你的澄清:)
- @不,你没有。它是在C 5.0而不是4.0中更改的。也没有C 3.5这样的东西。
- @servy no i使用C 4.0编译器Microsoft(R)Visual C编译器版本4.0.30319.17929有不同的输出
- @那么你错了。它在C 5.0中被更改。4.0编译器不会产生这个结果。
- @servy:虽然没有C 3.5语言,但是有一个编译器版本是3.5。编译器版本号与它们附带的框架版本匹配,而不是与它们分析的语言匹配。是的,这是不必要的混乱,我衷心希望我的前同事们能把他们的版本控制故事讲清楚。这是微软长期存在的问题。
- @是的,是的。这是截图jmp.sh/b/vqqmasiuioey9jbyahpy
- @Ericlippert非常感谢您的澄清:)
- @很好,也许Eric可以进一步澄清版本控制系统。您正在根据C 5.0语言规范进行编译。显然,您使用的C编译器版本能够针对C 5.0语言进行编译。这是一个在这里一直备受关注的特性,因为人们每天都会发布这个棘手的问题好几次,当大多数新的C程序员使用C 3-4时。
- @我同意你的看法,但我是在说编译器,你是在说语言版本
由于c_5,foreach中的循环变量被编译为存在于循环范围内,而不是在循环范围外。
这意味着当您关闭循环变量时,会得到不同的结果。
下面是埃里克·利珀特对原始问题的看法。
- 这是因为C 5.0,而不是.NET 4.0。
- 抓住了。谢谢。
- 这并不能回答问题。操作要求在C 4.0。但是你要用C 5.0
- OP询问关于.net4。这是观察结果的唯一可能性。
- 为了兼容性,在foreach循环中使用var t=num;。
- 好多了。之前的问题是C 4.0。现在编辑
- @哈比我很清楚这一点,所以我很困惑欧普是如何得出这个结果的,也很困惑这个答案。现在我明白了。困惑是问题是错误的。
- @sriramsakthivel安装4.5会更改.NET 4.0的行为,因为它在不更改版本号的情况下更新了BCL。
- @Scottchamberlain是的,IIRC也会改变.NET 3.5的行为。
- @sriramsakthivel刚刚测试过,你是对的。
您已经访问了一个闭包内的变量,因此编译器的不同版本的结果会有所不同。
在C 5.0中,变量在循环的每次迭代中都被重新定义,而在以前的C版本中,它只被定义了一次。
有关详细信息,请参阅Eric Lippert的精彩博客文章
更值得注意的是,开头一段:
UPDATE: We are taking the breaking change. In C# 5, the loop variable of a foreach will be logically inside the loop, and therefore closures will close over a fresh copy of the variable each time. The"for" loop will not be changed. We return you now to our original article.
- 变量的作用域与.NET版本无关。它与C的版本有关。它在C 5.0中被更改。
- 你读过埃里克的博客We are taking the breaking change. In C# 5吗?
- @是的,我澄清了,谢谢。
- 是的,在用.NET 3.5编译的VS2012中,它工作得很好。
- @alessandrod'andria这是因为您使用的是C 5.0编译器。使用的.NET版本不相关。
- @正是我想指出的。