我开始更多地关注LINQ引擎,我无法理解一些LINQ扩展方法的重载。
例如,假设我正在使用.Where()查询DbContext。我总是传递一个标准的Func<>,而不是表达式<>所述Func<>以下示例查询:
var db = new MyContext();
var foo = db.products.Where(p => p.Category == "books");
这是我困惑的地方。当我查看可用的方法签名时,我会假设我在上面使用的重载将返回一个IEnumerable ......但它实际上返回了一个IQueryable。如果IQueryable重载期望一个Expression而不仅仅是一个Func,这怎么可能呢?感觉就像编译器以某种方式帮助我(在这种情况下)为我构建表达式,但我找不到解释是否是这种情况的资源。谢谢!
答案 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表达式自动为你构建表达式树,这就是这里发生的事情。