zoukankan      html  css  js  c++  java
  • 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 customers
        group c by c.Country into g
    select new { Country=c.Country , Customer = g.Count()}

       转换为

    from g in
    from c in customers
    group c by c.Country
    select new { Country = g.Key, CustCount = g.Count() }

       最终转换为 

    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 customers
    where 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 customers
    select c

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

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

    from c in customers
    select 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 }) 
      

      带有 orderby 子句的查询表达式 
      from x in e 
      orderby k1 , k2 , … , kn 
       
      转换为 
      from x in ( e ) . 
      OrderBy ( x => k1 ) . 
      ThenBy ( x => k2 ). 
      … . 
      ThenBy ( x => kn ) 
       
      如果排序子句指定 descending 方向指示器,则将改为生成对 OrderByDescending 或 
    ThenByDescending 的调用。

    转换规则实例演示

      我们假定,在下面的每个查询表达式中没有 let、 where、 join 或 orderby 子句,并且最多只有一个初始 from 子句。 
       
      示例1:

      from c in customers
      from o in c.Orders
      select new { c.Name, o.OrderID, o.Total }

      转换为

    customers.
    SelectMany(c => c.Orders,(c,o) => new { c.Name, o.OrderID, o.Total })

      示例2:  

    from c in customers
    from o in c.Orders
    orderby o.Total descending
    select new { c.Name, o.OrderID, o.Total }

      转换为

    from * in customers.SelectMany(c => c.Orders, (c,o) => new { c, o })
    orderby o.Total descending
    select new { c.Name, o.OrderID, o.Total }

      最终转换为

    customers.SelectMany(c => c.Orders, (c,o) => new { c, o }).OrderByDescending(x => x.o.Total).Select(x => new { x.c.Name, x.o.OrderID, x.o.Total })

      其中 x 是编译器生成的以其他方式不可见且不可访问的标识符。

      示例3:

    from o in orders
    let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
    where t >= 1000
    select new { o.OrderID, Total = t }

      转换为

    1 from * in orders.
    2 Select(o => new { o, t = o.Details.Sum(d => d.UnitPrice * d.Quantity) })
    3 where t >= 1000
    4 select new { o.OrderID, Total = t }

      最终转换为

    orders.Select(o => new { o, t = o.Details.Sum(d => d.UnitPrice * d.Quantity) }).Where(x => x.t >= 1000).Select(x => new { x.o.OrderID, Total = x.t })

      其中 x 是编译器生成的以其他方式不可见且不可访问的标识符。

      示例4:

    from c in customers
    join o in orders on c.CustomerID equals o.CustomerID
    select new { c.Name, o.OrderDate, o.Total }

      转换为

    customers.Join(orders, c => c.CustomerID, o => o.CustomerID,(c, o) => new { c.Name, o.OrderDate, o.Total })

      示例5:

    from c in customers
    join o in orders on c.CustomerID equals o.CustomerID into co
    let n = co.Count()
    where n >= 10
    select new { c.Name, OrderCount = n }

      转换为

    from * in customers.GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,
    (c, co) => new { c, co })
    let n = co.Count()
    where n >= 10
    select new { c.Name, OrderCount = n }

      最终转换为

    customers.GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,(c, co) => new { c, co }).Select(x => new { x, n = x.co.Count() }).Where(y => y.n >= 10).Select(y => new { y.x.c.Name, OrderCount = y.n)

      其中 x 和 y 是编译器生成的以其他方式不可见且不可访问的标识符。 
       
      示例6:

    from o in orders
    orderby o.Customer.Name, o.Total descending
    select o

      转换为 

     orders.OrderBy(o => o.Customer.Name).ThenByDescending(o => o.Total) 

    select 子句的转换

      from x in e select v 
      转换为 
      ( e ) . Select ( x => v ) 
      当 v 为标识符 x 时,转换仅为 
      ( e ) 
      

    Groupby 子句的转换

      from x in e group v by k 
      转换为 
      ( e ) . GroupBy ( x => k , x => v ) 
      当 v 为标识符 x 时,转换为 
      ( e ) . GroupBy ( x => k )

    转载来源:http://blog.csdn.net/honantic/article/details/46490995

  • 相关阅读:
    zookeeper项目使用几点小结
    Dubbo架构设计详解
    关于web.xml不同版本之间的区别
    bat定时执行,清除PHP缓存
    新闻列表标题省略样式
    php把时间格式化
    HTML5中的拖放
    Redis JAVA客户端 Jedis常用方法
    Redis 简介
    SpringBoot DataSource 配置说明
  • 原文地址:https://www.cnblogs.com/swfpt/p/6847246.html
Copyright © 2011-2022 走看看