Linq where 关键字与Where 扩展和表达式参数

发布于 2024-08-24 05:41:01 字数 765 浏览 7 评论 0 原文

根据所使用的语法,将表达式传递给 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扩展相同?

谢谢, 托马斯

Passing in an Expression to a Linq query behaves differently depending on syntax used, and I wonder why this is the case.

Let's say I have this very generic 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
(Delegate 'System.Func' does not take 1 arguments)

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 was just wondering why the compiler does not treat the where keyword the same as the Where extension?

Thanks,
Thomas

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

单身狗的梦 2024-08-31 05:41:01

涉及 where 子句的查询表达式的语法是(简化完整语法)

from identifier in expression where boolean-expression select expression

whereClause 不是布尔表达式。为了重述这一点,你必须说

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

Note that if whereClause were a Func you can get escaped

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

Note that

from x in e where f

is generated by the compiler Mechanicalally into

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

I say机械地,因为它执行此转换而不进行任何语义分析来检查方法调用的有效性等。在所有查询表达式都已转换为 LINQ 方法调用表达式之后,该阶段才会出现。

尤其

from c in _ctx.Companies where whereClause select c

是翻译成

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

这显然是无稽之谈。

合法的原因

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

是因为 IEnumerable.Where 具有接受 Func 的重载,并且存在从 ExpressionExpression 的隐式转换;Func>Func

The syntax for a query expression involving a where clause is (simplifying the complete grammar)

from identifier in expression where boolean-expression select expression

whereClause is not a boolean expression. To recitify this, you have to say

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

Note that if whereClause were a Func<Company, bool> you could get away with

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

Note that

from x in e where f

is translated mechanically by the compiler into

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

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,

from c in _ctx.Companies where whereClause select c

is translated to

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

which is clearly nonsensical.

The reason that

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

is legit is because IEnumerable<Company>.Where has an overload accepting a Func<Company, bool> and there is an implicit conversion from an Expression<Func<Company, bool>> to a Func<Company, bool>.

枕梦 2024-08-31 05:41:01

实际上,您可以将整个过程缩短为:

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

当您使用 LINQ 语法时,where 子句中的代码将转换为 Expression<>,它表示代码树。当您接受 Expression> 时,您表示您的方法接受代码树,该代码树由编译器从 C# 代码转换而来。

由于您已经有了代码树,因此必须将其直接传递给 Where() 方法,而不是使用 LINQ 语法。

You can actually shorten the whole thing to:

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

When you use the LINQ syntax, the code in the where clause is translated into an Expression<>, which represents a code tree. When you accept Expression<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.

难理解 2024-08-31 05:41:01

不同之处在于,在类似 sql 中,它期望计算结果为 bool 的表达式。但在Where方法中,表达式的类型可以是委托。

要强制第二个工作,您可以更改为 whereClause.Compile()(c) 或将参数更改为 Func; whereClausewhereClause(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 to Func<Company, bool> whereClause and whereClause(c)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文