LINQ表达式如何知道Where()在Select()之前?

本文关键字:Select 之前 表达式 何知道 Where LINQ | 更新日期: 2023-09-27 18:03:32

我正在尝试创建一个LINQ提供程序。我正在使用指南LINQ:构建一个IQueryable provider系列,并且我已经将代码添加到LINQ:构建一个IQueryable provider - Part IV。

我正在感受它是如何工作的以及它背后的想法。现在我被一个问题卡住了,这个问题不是代码问题,更多的是关于理解。

我正在发射这个语句:

QueryProvider provider = new DbQueryProvider();
Query<Customer> customers = new Query<Customer>(provider);
int i = 3;
var newLinqCustomer = customers.Select(c => new { c.Id, c.Name}).Where(p => p.Id == 2 | p.Id == i).ToList();

代码或表达式不知何故知道WhereSelect之前。但是怎么做,在哪里?

代码中没有办法对表达式进行排序,实际上调试模式下的ToString()显示Select在Where之前。

我试图使代码失败。正常情况下,我先做Where,然后做Select

那么表达式是如何排序的呢?我没有对指南中的代码做任何更改。

LINQ表达式如何知道Where()在Select()之前?

表达式按照你写它们的顺序被"解释"、"翻译"或"执行"——所以Where 出现在Select

之前

如果执行:

        var newLinqCustomer = customers.Select(c => new { c.Id, c.Name})
                                       .Where(p => p.Id == 2 | p.Id == i).ToList();

则在匿名类型的IEnumerableIQueryable上执行Where


如果执行:

        var newLinqCustomer = customers.Where(p => p.Id == 2 | p.Id == i)
                                       .Select(c => new { c.Id, c.Name}).ToList();

则在客户类型的IEnumerableIQueryable上执行Where


我唯一能想到的是,也许你看到一些生成的SQL,其中SELECT和where已被重新排序?在这种情况下,我猜在(例如)LINQ to SQL提供程序中有一个优化步骤,它采用SELECT Id, Name FROM (SELECT Id, Name FROM Customer WHERE Id=2 || Id=@i)并将其转换为SELECT Id, Name FROM Customer WHERE Id=2 || Id=@i -但这必须是特定于提供程序的优化。

不,在一般情况下(例如LINQ to Objects),选择将在where语句之前执行。把它想象成一个管道,你的第一步是转换,第二步是过滤。而不是反过来,如果你写Where…Select就会出现这种情况。

现在,LINQ提供程序可以自由地遍历表达式树并按照它认为合适的方式进行优化。但请注意,您不能更改表达式的语义。这意味着一个聪明的LINQ to SQL提供者会尝试将尽可能多的where子句拉入SQL查询中,以减少通过网络传输的数据量。但是,请记住Stuart的例子:并非所有查询提供程序都很聪明,部分原因是排除查询重新排序的副作用并不像看起来那么容易。