程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C# 3.0語言新特性(語言規范):7 查詢表達式

C# 3.0語言新特性(語言規范):7 查詢表達式

編輯:關於C語言

原文:《C# Version 3.0 Specification》,Microsoft
翻譯:lover_P
查詢表達式(Query Expression)為查詢提供了一種語言集成的語法,這種語法類似於關系和分級查詢語言,如SQL和XQuery。

query-expression:
from-clause  query-body

from-clause:
from  from-generators

from-generators:
from-generator
from-generators  ,  from-generator

from-generator:
identifIEr  in  expression

query-body:
from-or-where-clausesopt  orderby-caluseopt  select-or-group-clause  into-clauSEOpt

from-or-where-clauses:
from-or-where-clause
from-or-where-clauses  from-or-where-clause

from-or-where-clause:
from-clause
where-clause

where-clause:
where  boolean-expression

orderby-clause:
orderby  ordering-clauses

ordering-clauses:
ordering-clause
ordering-clauses  ,  ordering-clause

ordering-clause:
expression  ordering-directionopt

ordering-direction:
ascending
descending

select-or-group-clause:
select-clause
group-clause

select-clause:
selelct  expression

group-clause:
group  expression  by  expression

into-clause:
into  identifIEr  query-body

一個查詢表達式以一個from子句開始,以一個select或group子句結束。起始的from子句後可以跟零個或多個from或where子句。每個from子句都是一個生成器,該生成器引入了一個可以覆蓋整個序列的迭代變量;而每個where子句都是一個過濾器,該過濾器用於從結果中排出項目。最終的select或group子句根據迭代變量來指定結果的表現形式。select或group子句前面還可以有一個orderby子句,用以指定結果的順序。最後,可以用一個into子句通過將一個查詢的結果作為一個子查詢的生成器來“聯結”兩個查詢。

在查詢表達式中,具有多個生成器的from子句嚴格等價於多個順序的只具有一個生成器的from子句。

7.1 查詢表達式的翻譯

C# 3.0語言並沒有為查詢表達式指定確切的執行語義,而是將查詢表達式翻譯為對附著於查詢表達式模式(Query Expression Pattern)的方法的調用。特別地,查詢表達式分別被翻譯為對名為Where、Select、SelectMany、OrderBy、OrderByDescending、ThenBy、ThenByDescending和GroupBy的方法的調用,這些方法有著預期的簽名和返回值類型。這些方法既可以是待查詢對象的實例方法,也可以是對象外部的擴展方法。這些方法進行著實際的查詢工作。

將查詢表達式翻譯為方法調用的過程是一個語法映射過程,發生在任何類型綁定或重載抉擇的執行之前。翻譯的結果可以保證語法正確,但不一定保證產生語義正確的C#代碼。在查詢表達式翻譯之後,產生的方法調用作為一般的方法調用進行處理,這時會依次發現錯誤,如方法不存在、參數類型錯誤或對一個范型方法的類型推斷失敗等。

後面的一系列示例依次演示了查詢表達式的翻譯。在後面的某一節中給出了翻譯規則的正式描述。

7.1.1 where子句

查詢表達式中的一個where子句:

from c in customers

where c.City == "London"

select c

將被翻譯為對一個Where方法的調用,其參數為合並了迭代變量和where子句中的表達式所得到的拉姆達表達式:

customers.

Where(c => c.City == "London")

7.1.2 select子句

上面的例子演示了選擇了最內部的迭代變量的select子句是如何通過翻譯為方法調用被消除的。

一個選擇了並非最內部的迭代變量的select子句:

from c in customers

where c.City == "Longdon"

select c.Name

將被翻譯為一個Select方法調用,其參數是一個拉姆達表達式:

customers.

Where(c => c.City == "London").

Select(c => c.Name)

7.1.3 group子句

一個group子句:

from c in customers

group c.Name by c.Country

將被翻譯為對GroupBy方法的調用:

customers.

GroupBy(c => c.Country, c => c.Name)

7.1.4 orderby子句

一個orderby子句:

from c in customers

orderby c.Name

select new { c.Name, c.Phone }

將被翻譯為一個對OrderBy方法的調用,或者當指定了descending指示符時,被翻譯為一個對OrderByDescending方法的調用:

customers.

OrderBy(c => c.Name).

Select(c => new { c.Name, c.Phone })

另一個orderby子句:

from c in customers

orderby c.Country, c.Balance descending

select new { c.Name, c.Country, c.Balance }

將被翻譯為對ThenBy和ThenByDescending方法的調用:

customers.

OrderBy(c => c.Country).

ThenByDescending(c => c.Balance).

Select(c => new { c.Name, c.Country, c.Balance })

7.1.5 多重生成器

多重生成器:

from c in customers

where c.City == "London"

from o in c.Orders

where o.OrderDate.Year == 2005

select new { c.Name, o.OrderID, o.Total }

將被翻譯為對所有非最內部生成器的SelectMany方法調用:

customers.

Where(c => c.City == "London").

SelectMany(c =>

    c.Orders.

    Where(o => o.OrderDate.Year == 2005).

    Select(o => new { c.Name, o.OrderID, o.Total })

)

當多重生成器被一個orderby子句合並起來:

from c in customers, o in c.Orders

where o.OrderDate.Year == 2005

orderby o.Total descending

select new { c.Name, o.OrderID, o.Total }

一個附加的Select將被注入,用於收集排序表達式和最終的結果序列。讓OrderBy可以操作整個序列是有必要的。OrderBy之後,最終的結果將被提取出來:

customers.

SelectMany(c =>

    c.Orders.

    Where(o => o.OrderDate.Year == 2005).

    Select(o => new { k1 = o.Total, v = new { c.Name, o.OrderID, o.Total } })

).

OrderByDescending(x => x.k1).

Select(x => x.v)

7.1.6 into子句

一個into子句:

from c in customers

group c by c.Country into g

select new { Country = g.Key, CustCount = g.Group.Count() }

是嵌套查詢的一種很簡單的形式:

from g in

    from c in customers

    group c by c.Country

select new { Country = g.Key, CustCount = g.Group.Count() }

將被翻譯為:

customers.

GroupBy(c => c.Country).

Select(g => new { Country = g.Key, CustCount = g.Group.Count() })

7.2 查詢表達式模式

查詢表達式模式(Query Expression Pattern)建立了類型可以實現的方法的一套模式,用以支持查詢表達式。因為查詢表達式會被通過語法映射來翻譯為方法調用,因此類型在如何實現其查詢表達式模式上尤為靈活。例如,模式的這些方法可以被實現為實例方法或擴展方法,因為兩者具有完全一樣的調用語法;而方法的參數也可以是委托或表達式樹,因為拉姆達表達式可以轉換為這兩者。

下面給出了支持查詢表達式模式的范型類型C<T>的推薦形式。范型類型用於演示參數和結果類型之間正確的關系,也可以將模式實現為非范型類型。

delegate R Func<A, R>(A arg);

 

class C<T>

{

    public C<T> Where(Func<T, bool> predicate);

    public C<S> Select<S>(Func<T, S> selector);

    public C<S> SelectMany<S>(Func<T, C<S>> selector);

    public O<T> OrderBy<K>(Func<T, K> keyExpr);

    public O<T> OrderByDescending<K>(Func<T, K> keyExpr);

    public C<G<K, T>> GroupBy<K>(Func<T, K> keyExpr);

    public C<G<K, E>> GroupBy<K, E>(Func<T, K> keyExpr, Func<T, E> elemExpr);

}

 

class O<T> : C<T>

{

    public O<T> ThenBy<K>(Func<T, K> keySelector);

    public O<T> ThenByDescending<K>(Func<T, K> keySelector);

}

 

class G<K, T>

{

    public K Key { get; }

    public C<T> Group { get; }

}

上面的方法是用了一個范型委托類型Func<A, R>,也可以使用等價的其他委托或表達式樹類型,只要參數和結果類型之間存在正確的關系即可。

注意在推薦的C<T>和O<T>之間的關系中,要保證ThenBy和ThenByDescending方法只能用在OrderBy或OrderByDescending的結果上。同時請注意GroupBy結果的推薦形式,應該是一組具有Key和Group屬性的(匿名類型實例)序列。

標准查詢運算符(Standard Query Operators,在另外一個規范中描述)提供了查詢表達式的一個實現,這個實現可以用於所有實現了System.Collections.Generic.IEnumerable<T>接口的類型。

7.3 正式的翻譯規則

對一個查詢表達式的處理將重復、依次地應用下列翻譯規則。每個翻譯都一直應用這些規則直到不再發生任何給定的模式。

注意將會產生對OrderBy和ThenBy的調用的翻譯,如果相應的排序子句制定了descending指示符,將產生對OrderByDescending或ThenByDescending的調用。

l          包含了into子句的查詢:

q1 into x q2

將被翻譯為:

from x in (q1) q2

l          具有多個生成器的from子句:

from g1, g2, ... gn

將被翻譯為:

from g1 from g2 ... from gn

l          後面立即跟有where子句的from子句:

from x in e where f

將被翻譯為:

from x in (e).Where(x => f)

l          具有多個from子句、一個orderby子句和一個select子句的查詢表達式:

from x1 in e1 from x2 in e2 ... orderby k1, k2 ... select v

將被翻譯為:

(from x1 in e1 from x2 in e2 ...

select new { K1 = k1, K2 = k2 ..., V = v })

.OrderBy(x => x.K1).ThenBy(x => x.K2)...

.Select(x => x.V)

l          具有多個from子句、一個orderby子句和一個group子句的查詢表達式:

from x1 in e1 from x2 in e2 ... orderby k1, k2 ... group v by g

將被翻譯為:

(from x1 in e1 from x2 in e2 ...

select new { K1 = k1, K2 = k2 ..., V = v, G = g })

.OrderBy(x => x.K1).ThenBy(x => x.K2) ...

.GroupBy(x => x.G, x => x.V)

l          具有多個from子句和一個select子句的查詢表達式:

from x in e from x1 in e1 ... select v

將被翻譯為:

(e).SelectMany(x => from x1 in e1 ... select v)

l          具有多個from子句和一個group子句的查詢表達式:

from x in e from x1 in e1 ... group v by g

將被翻譯為:

(e).SelectMany(x => from x1 in e1 ... group v by g)

l          具有一個from子句、沒有orderby子句,並且具有一個select子句的查詢表達式:

from x in e select v

將被翻譯為:

(e).Select(x => v)

當v就是標識符x時,翻譯將被簡化為:

(e)

l          具有一個from子句、沒有orderby子句,並且具有一個group子句的查詢表達式:

from x in e group v by g

將被翻譯為

(e).GroupBy(x => g, x => v)

當v就是標識符x時,翻譯將被簡化為:

(e).GroupBy(x => g)

l          具有一個from子句、一個orderby子句和一個select子句的查詢表達式:

from x in e orderby k1, k2 ... select v

將被翻譯為:

(e).OrderBy(x => k1).ThenBy(x => k2) ...

.Select(x => v)

當v就是標識符x時,翻譯將被簡化為:

(e).OrderBy(x => k1).ThenBy(x => k2) ...

l          具有一個from子句、一個orderby子句和一個group子句的查詢表達式:

from x in e orderby k1, k2 ... group v by g

將被翻譯為:

(e).OrderBy(x => k1).ThenBy(x => k2) ...

.GroupBy(x => g, x => v)

當v就是標識符x時,翻譯將被簡化為:

(e).OrderBy(x => k1).ThenBy(x => k2) ...

.GroupBy(x => g)

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved