LINQ与Method表达式的差异

Ash*_*ohn 6 c# linq

为什么Linq表达式IL会导致省略Select投影,而相应的方法表达式会保留Select投影?

我想这两段代码也是一样的.

 var a = from c in companies
                where c.Length >10
                select c;

//

var b = companies.Where(c => c.Length > 10).Select(c => c);

//IL - LINQ

IEnumerable<string> a = this.companies.
Where<string>(CS$<>9__CachedAnonymousMethodDelegate1);

//IL

   IEnumerable<string> b = this.companies.Where<string>
   (CS$<>9__CachedAnonymousMethodDelegate4).Select<string, string>
   (CS$<>9__CachedAnonymousMethodDelegate5);
Run Code Online (Sandbox Code Playgroud)

那为什么IL的区别呢?

编辑:那么为什么

  var a = from c in companies
           select c;
Run Code Online (Sandbox Code Playgroud)

即使在IL内部也会导致SELECT投影.它也可以省略吗?

mez*_*tou 5

C#编译器很聪明,可以从Linq中删除无用的语句.选择c没用,所以编译器将其删除.当你编写Select(c => c)时,编译器不能说该指令是无用的,因为它是一个函数调用,所以它不会删除它.如果你删除它自己IL变得相同.

编辑:Linq是一种"描述性"语言:你说出你想要的东西,编译器就可以很好地转换它.您对该转换没有任何控制权.编译器尝试优化函数调用而不使用Select因为你没有做投影所以它没用.当你编写Select(c => c)时,你会明确地调用一个函数,所以编译器不会删除它.

var a = from c in companies select c;
var a = c.Select(elt=>elt);
Run Code Online (Sandbox Code Playgroud)

在此示例中,Select非常有用.如果你删除它有一个类型的c; 否则a是IEnumerable


Ani*_*Ani 5

@mexianto当然是正确的,这是一个编译器优化.

请注意,这在"退化查询表达式"下的语言规范中明确指出.还要注意编译器足够聪明,执行优化,这样做会返回原始源对象(用户可能希望使用简并查询使客户端难以改变源对象,假设它是可变的).

7.16.2.3简并查询表达式

表单的查询表达式

from x in e select x
Run Code Online (Sandbox Code Playgroud)

被翻译成

( e ) . Select ( x => x ) 
Run Code Online (Sandbox Code Playgroud)

[...]简并查询表达式是一个简单地选择源元素的表达式.翻译的后期阶段通过用其源替换它们来移除由其他翻译步骤引入的退化查询.但是,确保查询表达式的结果永远不是源对象本身是很重要的,因为这会向查询客户端显示源的类型和标识.因此,此步骤通过在源上显式调用Select来保护直接在源代码中编写的退化查询.然后由Select和其他查询运算符的实现者来确保这些方法永远不会返回源对象本身.


Max*_*erl 3

在第二个示例中,对 Select 的调用并不多余。如果省略 Select 调用,查询将仅返回原始集合,而 Select 返回 IEnumerable。

在第一个示例中,Where 已经返回 IEnumerable 并且 select 子句不执行任何工作,因此将其省略。