Linq where the keyword vs. Where are the extension parameters and expressions

Passing an expression into a Linq query behaves differently depending on the syntax used, and I wonder why this is.

Say I have this very general function

private IEnumerable<Company> GetCompanies(Expression<Func<Company, bool>> whereClause) 

The following implementation works as expected

 private IEnumerable<Company> GetCompanies(Expression<Func<Company, bool>> whereClause) { return (from c in _ctx.Companies.Where(whereClause) select c); } 

But this next implementation does not compile (The delegate "System.Func" does not accept 1 argument)

 private IEnumerable<Company> GetCompanies(Expression<Func<Company, bool>> whereClause) { return (from c in _ctx.Companies where whereClause select c); } 

Obviously, I can just use the first syntax, but I'm just wondering why the compiler doesn't treat the where keyword in the same way as the Where extension?

Thank you Thomas

+6
linq extension-methods delegates
source share
3 answers

The syntax of the query expression with the where clause (simplifying the full grammar)

 from identifier in expression where boolean-expression select expression 

whereClause not a boolean expression. To repeat this you must say

 from c in _ctx.Companies where whereClause.Compile()(c) select c; 

Note that if whereClause was Func<Company, bool> , you could leave with

 from c in _ctx.Companies where whereClause(c) select c; 

note that

 from x in e where f 

mechanically passed by the compiler to

 (from x in e).Where(x => f) 

I speak mechanically because he performs this translation without any semantic analysis to verify the correctness of method calls, etc. This step begins later after all query expressions have been translated into LINQ method call expressions.

In particular,

 from c in _ctx.Companies where whereClause select c 

translates to

 _ctx.Companies.Where(c => whereClause).Select(c) 

which is clearly pointless.

Reason for which

 from c in _ctx.Companies.Where(whereClause) select c 

is legal because IEnumerable<Company>.Where has an overload that accepts Func<Company, bool> , and there is an implicit conversion from Expression<Func<Company, bool>> to Func<Company, bool> .

+3
source share

In fact, you can shorten all of this:

 private IEnumerable<Company> GetCompanies(Expression<Func<Company, bool>> whereClause) { return _ctx.Companies.Where(whereClause); } 

When you use LINQ syntax, the code in the where clause is converted to Expression<> , which is a tree of code. When you accept Expression<Func<Customer, bool>> , you say that your method accepts a code tree that is converted from C # code by the compiler.

Since you already have a code tree, you should pass it directly to the Where() method, and not use the LINQ syntax.

+2
source share

The difference is in sql-like, where it expects an expression that evaluates to bool. But in the Where method, the type of expression can be a delegate.

to make the second one work, you can change to whereClause.Compile()(c) or change the parameter to Func<Company, bool> whereClause and whereClause(c)

0
source share

All Articles