传递Func&lt;&gt;到IQueryable vs Expression <func <>&gt; </func <>

时间:2014-07-21 14:53:55

标签: c# linq

我开始更多地关注LINQ引擎,我无法理解一些LINQ扩展方法的重载。

例如,假设我正在使用.Where()查询DbContext。我总是传递一个标准的Func&lt;&gt;,而不是表达式&lt;&gt;所述Func&lt;&gt;以下示例查询:

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

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

4 个答案:

答案 0 :(得分:2)

  

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

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

答案 1 :(得分:1)

  

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

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

  

我无法找到解释是否属于这种情况的资源

来自MSDN

  

当lambda表达式分配给类型为Expression<TDelegate>的变量时,编译器会发出代码来构建表示lambda表达式的表达式树。

答案 2 :(得分:1)

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

答案 3 :(得分:0)

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

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