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

  • 相关阅读:
    104.Maximum Depth of Binary Tree
    103.Binary Tree Zigzag Level Order Traversal
    102.Binary Tree Level Order Traversal
    101.Symmetric Tree
    100.Same Tree
    99.Recover Binary Search Tree
    98.Validate Binary Search Tree
    97.Interleaving String
    static静态初始化块
    serialVersionUID作用
  • 原文地址:https://www.cnblogs.com/swfpt/p/6847246.html
Copyright © 2011-2022 走看看