Passing Func<> to IQueryable vs Expression<Func<

本文关键字:lt Func vs Expression IQueryable gt Passing to | 更新日期: 2023-09-27 18:14:10

我开始在LINQ的引子下多看一点,我很难理解一些LINQ扩展方法的重载。

例如,假设我正在使用. where()查询DbContext。我总是传递一个标准的Func<>,而不是所述Func<>的表达式<>。下面的查询示例:

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

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

Passing Func<> to IQueryable vs Expression<Func<

感觉编译器在某种程度上帮助了我(在这种情况下)构建表达式

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

感觉编译器在某种程度上帮助了我(在这种情况下)构建表达式

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

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

从MSDN:

当将lambda表达式赋值给Expression<TDelegate>类型的变量时,编译器发出代码来构建表示该lambda表达式的表达式树。

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

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

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