为什么这些linq输出不同?

Roh*_*ash 35 c# linq

第一个声明:

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');
Run Code Online (Sandbox Code Playgroud)

产量String.Join("", query):"Nt wht y mght xpct"

第二个声明:

query = "Not what you might expect";

foreach (char vowel in "aeiou")
    query = query.Where (c => c != vowel);
Run Code Online (Sandbox Code Playgroud)

产量String.Join("", query):"Not what yo might expect"

这些陈述的输出是不同的.任何人都可以解释原因吗?

Bot*_*000 57

如果你使用的C#版本低于5.0(这是固定的),这就是原因:

查询中的lambda捕获循环变量vowel.
因为Linq喜欢使用延迟执行,所以在查询执行之前(通过遍历它)不会读取此引用的值,这是在foreach循环完成之后.此时,最近的值vowelu,这就是您获得意外输出的原因.

您可以通过将值复制到另一个临时变量(或升级到C#5.0)来解决此问题.

试试这个:

query = "Probably what you might expect";

foreach (char vowel in "aeiou") {
    char currentVowel = vowel;
    query = query.Where (c => c != currentVowel );
}
Run Code Online (Sandbox Code Playgroud)

  • @Teejay我还没有遇到过需要原始行为的案例.此外,LINQ的执行模型没有被这种改变修改,只是foreach循环. (6认同)
  • 哦,[我看到](http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx),在C#5中. (3认同)
  • 想知道为什么这个已经在.net 4.5中"修复"了.由于LINQ是按定义延迟执行的,我不明白为什么要修改旧行为,这实际上更正确. (2认同)

Hon*_*tan 13

这是因为你在vowel变量上创建了一个闭包,它随时间变化.将其值存储在单独的变量中,它将起作用:

query = "Not what you might expect";

foreach (char vowel in "aeiou")
{
    var current = vowel;
    query = query.Where (c => c != current);
}
Run Code Online (Sandbox Code Playgroud)


Ham*_*yan 11

阅读关闭.如果您使用.NET 4.0和以下,您将得到不同的结果.在.NET 4.5此行为中更改(固定).另请参见编译器如何扩展foreach.