开发者

Differences in LINQ vs Method expression

开发者 https://www.devze.com 2023-04-08 23:34 出处:网络
Why the Linq expression IL results in omission of the Select projection whereas the开发者_C百科 corresponding method expression keeps the Select projection ?

Why the Linq expression IL results in omission of the Select projection whereas the开发者_C百科 corresponding method expression keeps the Select projection ?

I suppose these two pieces of code does the same.

 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);

Then why the difference in IL?

EDITED : then why

  var a = from c in companies
           select c;

result in SELECT projection even inside IL. it can also be omitted right ?


The C# compiler is clever and remove useless statement from Linq. Select c is useless so the compiler remove it. When you write Select(c=>c) the compiler can't say that's the instruction is useless because it' a function call and so it doesn't remove it. If you remove it yourself IL become the same.

EDIT : Linq is a "descriptive" language : you say what you want and the compiler transforms it well. You don't have any control on that transformation. The compiler try to optimize function call and don't use Select because you don't do projection so it's useless. When you write Select(c => c) you call a function explicitely so the compiler won't remove it.

var a = from c in companies select c;
var a = c.Select(elt=>elt);

Select is usefull in this example. If you remove it a has the type of c; otherwise a is an IEnumerable


@mexianto is of course correct that this is a compiler optimization.

Note that this is explicitly called out in the language specification under "Degenerate Query expressions." Also note that the compiler is smart enough to not perform the optimization when doing so would return the original source object (the user might want to use a degenerate query to make it difficult for the client to mutate the source object, assuming that it is mutable).

7.16.2.3 Degenerate query expressions

A query expression of the form

from x in e select x

is translated into

( e ) . Select ( x => x ) 

[...] A degenerate query expression is one that trivially selects the elements of the source. A later phase of the translation removes degenerate queries introduced by other translation steps by replacing them with their source. It is important however to ensure that the result of a query expression is never the source object itself, as that would reveal the type and identity of the source to the client of the query. Therefore this step protects degenerate queries written directly in source code by explicitly calling Select on the source. It is then up to the implementers of Select and other query operators to ensure that these methods never return the source object itself.


In your second example, the call to Select is not redundant. If you would omit the Select call, the query would just return the original collection, whereas Select returns an IEnumerable.

In your first example, Where already returns an IEnumerable and the select clause doesn't do any work, so it is omitted.


Because in the query version there is no actual select projecting 'c' into something else, it is just passing on 'c' as-is. Which results in only a call to 'Where'.

In the second variation, you explicitly call 'Select' and thus do a projection. Yes, you are only returning the same objects, but the compiler will not see this.

0

精彩评论

暂无评论...
验证码 换一张
取 消