【问题标题】:Passing Func<> to IQueryable vs Expression<Func<>>将 Func<> 传递给 IQueryable 与 Expression<Func<>>
【发布时间】:2014-07-21 14:53:54
【问题描述】:

我开始更深入地了解 LINQ,但我无法理解一些 LINQ 扩展方法重载。

例如,假设我正在使用 .Where() 查询 DbContext。我总是传递标准的 Func,而不是所述 Func 的 Expression。下面的示例查询:

var db = new MyContext();
var foo = db.products.Where(p => p.Category == "books");

这就是我感到困惑的地方。当我查看可用的方法签名时,我会假设我上面使用的重载将返回一个 IEnumerable ......但它实际上返回一个 IQueryable。如果 IQueryable 重载需要一个表达式而不是一个函数,这怎么可能?感觉编译器通过(在这种情况下)为我构建表达式以某种方式帮助我,但我找不到解释是否是这种情况的资源。谢谢!

【问题讨论】:

  • 如果您使用的是实体框架,那么在您的查询中使用 Func 可能会很糟糕。我们遇到过使用 lamda 中的 Func 查询数据库的情况。结果是 EF 将整个表返回给客户端,然后在客户端使用 Func 进行过滤。使用实体框架时,您绝对应该使用 Expression>。

标签: c# linq


【解决方案1】:

感觉编译器通过(在这种情况下)为我构建表达式以某种方式帮助了我

这正是正在发生的事情。编译器可以将 lambdas(只要它们没有“语句体”)解释为委托或表达式树。 Queryable.Where&lt;T&gt;(this IQuerayble&lt;T&gt;, ...) 扩展方法优先于 Enumerable.Where&lt;T&gt;(this IEnumerable&lt;T&gt;, ...) 扩展方法,因此编译器选择将您的谓词解释为表达式树。

【讨论】:

  • 感谢您回答我的后续问题(优先构建表达式)。
  • @gerg 不,不是“构建表达式”优先;就是那个IQuerayble&lt;T&gt; : IEnumerable&lt;T&gt;IQuerayble&lt;T&gt; 优先。表达式树发生在 方法重载解析之后。
【解决方案2】:

感觉编译器通过(在这种情况下)为我构建表达式以某种方式帮助我

正确,编译器将 lambda 编译为 Expression 而不是 Func

我找不到解释是否是这种情况的资源

来自MSDN

将 lambda 表达式分配给 Expression&lt;TDelegate&gt; 类型的变量时,编译器会发出代码来构建表示 lambda 表达式的表达式树。

【讨论】:

    【解决方案3】:

    在该示例中,您没有传递Func。您正在传递Expression。 lambda 可以根据其周围的上下文编译为委托或表达式。在这种情况下,它周围的上下文需要一个表达式,所以这就是 lambda 编译成的内容。如果您确实传入了 Func 而不是 lambda(可能是两者之一),那么您的结果将得到 IEnumerable,而不是 IQueryable

    【讨论】:

      【解决方案4】:

      编译器可以从一个lamba表达式自动为你构建一个表达式树,这就是这里发生的事情。

      http://msdn.microsoft.com/en-gb/library/bb397951.aspx

      【讨论】:

        猜你喜欢
        • 2014-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-04
        相关资源
        最近更新 更多