[深入学习C#]LINQ查询表达式详解(2)

简介

  C#在执行LINQ查询表达式的时候,并不会指定其执行语义,而是将查询表达式转换为遵循查询表达式模式的方法的调用。具体而言,查询表达式将转换为以下名称的调用:Where、Select、SelectMany、Join、GroupJoin、OrderBy、OrderByDescending、ThenBy、ThenByDescending、GroupBy、Cast等等。   如同在前文中提到的用扩展方法和Lambda表达式简化LINQ查询表达式一般,这也是对查询表达式的一种转换。简化后的方法其实就是LINQ查询的实际执行。   本文中用来示例的代码,参数设定都沿用上一篇文章的设定。

转换规则简述

  从查询表达式到方法调用的转换是一种句法映射,在执行任何类型绑定或重载决策之前发生。该转换可以保证在句法上正确,但不能保证生成语法正确的 C# 代码。转换查询表达式后,以常规方法调用的方式处理生成的方法调用,而这进而可能暴露错误,例如在方法不存在、参数类型错误或方法为泛型方法且类型推断失败这些情况下。   不允许对查询表达式中的范围变量进行赋值。但允许 C# 实现在某些时候以不实施此限制,因为对于此处介绍的句法转换方案,有些时候可能根本无法实施此限制。   某些转换使用由 * 指示的透明标识符注入范围变量。

转换规则讲解带继续符的select和groupby子句的查询表达式的转换

  继续符是指 into 操作符,带有继续符的查询表达式类似如下:    from ···into x ···    转换为    from x in (from ···) ···    示例:

from c in customersgroup c by c.Country into g

   转换为

from g infrom c in customersgroup c by c.Country

   最终转换为 

customers.GroupBy(c => c.Country).Select(g => new { Country = g.Key, CustCount = g.Count() })含有显式范围变量类型的查询表达式的转换

   显式指定范围变量类型的 from 子句    from T x in e    转换为    from x in (e).Cast<T>()

   显式指定范围变量类型的 join 子句    join T x in e on k1 equals k2    转换为    join x in (e).Cast<T>()

   示例: 

from Customer in customerswhere c.City == “London”select c

   转换为

from c in customers.Cast<Customer>()where c.City == “London”select c

   最终转换为

customers.Cast<Customer>().Where(c=>c.City==”London”)

   显式范围变量类型对于查询实现非泛型 IEnumerable 接口的集合很有用,但对于实现泛型IEnumerable 接口的集合没什么用处。如果 customers 属于 ArrayList 类型,则在面的示例中即会如此。   

退化查询表达式的转换

   退化查询表达式,是指选择源元素本身的查询,如:

from c in customersselect c

  确保查询表达式的结果永不为源对象本身非常重要,因为这样会向查询的客户端暴露源的类型和标识符。因此,在查询表达式为退化查询的时候,可通过在源上显式调用 Select 来保护直接以源代码形式写入的简并查询。然后,由 Select 实施者及其他查询操作员确保这些方法永远不会返回源对象本身。

  退化查询表达式如下:   from x in e select x   转换为   (e).Select(x=>x)   示例:

from c in customersselect c

  转换为

customers.Select(c => c)from、 let、 where、 join 和 orderby 子句的转换转换规则

  带有另一个 from 子句且后接一个 select 子句的查询表达式   from x1 in e1   from x2 in e2   select v   转换为   (e1).SelectMany( x1 => e2 , ( x1 , x2 ) => v )

  带有另一个 from 子句且后接一个 select 子句的查询表达式   from x1 in e1   from x2 in e2   ···   转换为   from * in (e1).SelectMany( x1 => e2 , ( x1 , x2 ) => new { x1 , x2 })

  带有 let 子句的查询表达式   from x in e   let y=f   转换为   from * in (e).Select( x => new { x , y = f })

  带有 where 子句的查询表达式   from x in e   where f   ···   转换为   from x in (e).Where( x => f )

  带有 join 子句(不含 into)且后接 select 子句的查询表达式   from x1 in e1   join x2 in e2 on k1 equals k2   select v   转换为   ( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => v )

  带有 join 子句(不含 into)且后接除 select 子句之外的其他内容的查询表达式   from x1 in e1   join x2 in e2 on k1 equals k2   …   转换为   from * in ( e1 ) . Join(   e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => new { x1 , x2 })   …

  带有 join 子句(含 into)且后接 select 子句的查询表达式   from x1 in e1   join x2 in e2 on k1 equals k2 into g   select v   转换为   ( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => v )      带有 join 子句(含 into)且后接除 select 子句之外的其他内容的查询表达式   from x1 in e1   join x2 in e2 on k1 equals k2 into g   …   转换为   from * in ( e1 ) . GroupJoin(   e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => new { x1 , g })   …

可我,仍在旅行的路上徘徊。等待着每一辆经过的车,让我走到更远的地方。

[深入学习C#]LINQ查询表达式详解(2)

相关文章:

你感兴趣的文章:

标签云: