LINQ to SQL 如何知道委托中有什么?

How does LINQ to SQL know what's inside a delegate?

有了 entity framework,我们可以做到:

MyContext context = ... // a normal EF context 

var products =  context.Products.Where(p => p.Location == "France") ; 

var products =  context.Products.Where(p => p.CategoryId == 54) ;

它们都在等效的 SQL 查询中翻译。

好的,但是在那边的某个地方,有一段代码可以处理这个问题:

public static IEnumerable<T> Where(Func<bool, T> func) {
     ......
}

从那个 Where 函数,LINQ to SQL 怎么知道 func 的实现是什么?

也许是显而易见的答案,但我真的找不到。

您真的应该对您的代码执行 Go To Definition。用于 LINQ-to-SQL 和 Entity Framework 的 function

IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)

包含在System.Linq.Queryable that uses expression trees中,这是一个能够"describe"段代码的结构。一点引述:

Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y.

例如,您的第一个表达式

var products = context.Products.Where(p => p.Location == "France"); 

由 C# 编译器转换为以下代码:

ParameterExpression par = Expression.Parameter(typeof(Product), "p");
LambdaExpression lambda = Expression.Lambda(
    Expression.Equal(
        Expression.Property(par, "Location"), 
        Expression.Constant("France")), 
    par);

var products = context.Products.Where(lambda); 

现在...虽然创建表达式树非常简单,但反向操作(取消构建表达式树并创建查询)却非常复杂。大大复杂的头疼。近乎魔法级的情结:-)

问题不在于取消构建表达式树。那很容易。您使用 ExpressionVisitor 就完成了。问题是合并 LINQ 查询的各个层并理解程序员想要获得的内容。

我要补充一点,IL(.NET 的 "assembly")级别足够高,可以对其进行反编译(例如,参见 IlSpy). There is at least a library, DelegateDecompiler,它能够将委托反编译为一个表达式树,所以即使没有表达式树,LINQ-to-SQL 和 EF 也可以使用类似的方法和反编译方法直接用于 SQL 语言。