Linq where 关键字与Where 扩展和表达式参数
根据所使用的语法,将表达式传递给 Linq 查询的行为会有所不同,我想知道为什么会出现这种情况。
假设我有一个非常通用的函数
private IEnumerable<Company>
GetCompanies(Expression<Func<Company, bool>> whereClause)
以下实现按预期工作
private IEnumerable<Company>
GetCompanies(Expression<Func<Company, bool>> whereClause)
{
return (from c in _ctx.Companies.Where(whereClause) select c);
}
但下一个实现无法编译 (委托“System.Func”不接受 1 个参数)
private IEnumerable<Company>
GetCompanies(Expression<Func<Company, bool>> whereClause)
{
return (from c in _ctx.Companies where whereClause select c);
}
显然我可以只使用第一个语法,但我只是想知道为什么编译器不将 where 关键字与Where扩展相同?
谢谢, 托马斯
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
涉及
where
子句的查询表达式的语法是(简化完整语法)whereClause
不是布尔表达式。为了重述这一点,你必须说Note that if
whereClause
were aFunc
you can get escapedNote that
is generated by the compiler Mechanicalally into
I say机械地,因为它执行此转换而不进行任何语义分析来检查方法调用的有效性等。在所有查询表达式都已转换为 LINQ 方法调用表达式之后,该阶段才会出现。
尤其
是翻译成
这显然是无稽之谈。
合法的原因
是因为
IEnumerable.Where
具有接受Func
的重载,并且存在从Expression
Expression
的隐式转换;Func>
到Func
。The syntax for a query expression involving a
where
clause is (simplifying the complete grammar)whereClause
is not a boolean expression. To recitify this, you have to sayNote that if
whereClause
were aFunc<Company, bool>
you could get away withNote that
is translated mechanically by the compiler into
I say mechanically because it performs this translation without doing any semantic analysis to check validity of the method calls etc. That stage comes later after all query expressions have been translated to LINQ method-invocation expressions.
In particular,
is translated to
which is clearly nonsensical.
The reason that
is legit is because
IEnumerable<Company>.Where
has an overload accepting aFunc<Company, bool>
and there is an implicit conversion from anExpression<Func<Company, bool>>
to aFunc<Company, bool>
.实际上,您可以将整个过程缩短为:
当您使用 LINQ 语法时,
where
子句中的代码将转换为Expression<>
,它表示代码树。当您接受Expression>
时,您表示您的方法接受代码树,该代码树由编译器从 C# 代码转换而来。由于您已经有了代码树,因此必须将其直接传递给
Where()
方法,而不是使用 LINQ 语法。You can actually shorten the whole thing to:
When you use the LINQ syntax, the code in the
where
clause is translated into anExpression<>
, which represents a code tree. When you acceptExpression<Func<Customer, bool>>
, you are saying that your method accepts a code tree, which is converted from C# code by the compiler.Since you already have the code tree, you have to pass it directly to the
Where()
method, rather than using LINQ syntax.不同之处在于,在类似 sql 中,它期望计算结果为 bool 的表达式。但在Where方法中,表达式的类型可以是委托。
要强制第二个工作,您可以更改为
whereClause.Compile()(c)
或将参数更改为Func; whereClause
和whereClause(c)
The difference is that in sql-like where it expects expression that evaluates to bool. But in Where method the type of expression can be the delegate.
to force second to work you can change to
whereClause.Compile()(c)
or change parameter toFunc<Company, bool> whereClause
andwhereClause(c)