C# 3.0语言新特性(语言规范):7 查询表达式

规范

原文:《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)

 

时间: 2024-08-04 06:51:06

C# 3.0语言新特性(语言规范):7 查询表达式的相关文章

AS代码2.0:新的语言元素

Flash的ActionScript(简称AS)代码控制是Flash实现交互性的重要组成部分,也是区别于其他动画软件的看家本领.今年新发布的Flash MX Professional 2004的动作脚本语言已经升级到2.0,它是一种面向对象的脚本语言,执行ECMA-262脚本语言规范,支持继承.强类型和事件模型.使用动作脚本语言2.0可以编写出更加稳健的脚本. 动作脚本语言2.0的新特性包括:新的语言元素.改进的编辑和调试工具.引入更多.的面向对象编程模型. 本系列文章将向大家详细介绍AS代码2

《Visual C++ 2012 开发权威指南》——第2章 Visual C++2012语言新特性2.1 Visual C++2012的语言新特性(1)

第2章 Visual C++2012语言新特性 Visual C++ 2012 开发权威指南 有一种新的C++标准就有一种新版本的Visual C++,新的版本Visual C++将更加符合C++标准!在其发展过程中新的C++标准被(乐观)称为C++0x.它最后被发布在2011年,现在称为C++11. 对于Visual C++,它有三个不同版本的数字,有不同的内部版本和编译器版本(cl.exe和_MSC_VER宏-显示不同,因为我们C++编译器早在Visual C++中的"可视化").

《Visual C++ 2012 开发权威指南》——2.2 Visual C++2012的语言新特性(2)

2.2 Visual C++2012的语言新特性(2) Rvalue引用:N1610"Rvalues类对象的初始化的澄清"是早期尝试启用无rvalue引用move 语意. 这些新规则还没有完全实现VC11开发者预览中. Rvalue引用v3.0添加自动生成的构造函数和移动赋值运算符在一定条件下的新规则.这不会进行中VC11,还将继续遵循的永远不会自动生成move构造函数/移动页本页的行为. 移动语义 Rvalue引用支持移动语义的实现,可以显著提高应用程序的性能.移动语义使能够调用资源

《Visual C++ 2012 开发权威指南》——2.3 Visual C++2012的语言新特性(3)

2.3 Visual C++2012的语言新特性(3) 在VC12(Visual C++2012),我们打算完全支持C++11标准库,但实施编译器功能可以自定义(另外,VC12不会完全实现C99标准库,已经通过引用纳入C++11标准库.注意本页和VC12已经有).这里是我们不断的变化的非详尽列表: 新头文件:......和. 进驻:根据需要由C++11,我们已经实现了emplace()/emplacefront()/emplace_back()/ emplace hint()/emplace_a

Spring 2.0的新特性点评

Spring2.0的发布恐怕算得上2006年Java社区的一件大事了.在Spring2.0发布附带的文档里面对2.0新特性做了概要的介绍,2.0的新特性是自然是我们最关注的方面: 一.Spring的XML配置引入XML Schema语法简化配置 在Spring1.x系列中,bean的配置文件使用DTD,没有namespace的分隔.2.0的一个非常大的改进是引入了XML Schema的namespace,因而可以将bean的配置文件做大幅度的简化.这些简化包括了对bean属性的各种简化,AOP配

《Ext JS实战》——1.4 Ext JS 3.0的新特性

1.4 Ext JS 3.0的新特性 Ext JS 2.0中引入的一些变化是颠覆性的,这就导致从级到2.0相当困难.这主要是因为这一版引入了一个更加现代的布局管理器以及一个崭新的.健壮的组件层次,许多Ext JS 1.x的代码都会因此而崩溃.值得庆幸的是,由于Ext JS 2.0的良好的工艺设计,从Ext JS 2.0到3.0的移植就非常容易了.尽管Ext JS 3.0新增的内容并不怎么神奇,不过最新的版本还是可圈可点的,有些新增的特性还是值得讨论的. 1.4.1 Ext JS通过Direct完

C#7.0中新特性汇总_C#教程

以下将是 C# 7.0 中所有计划的语言特性的描述.随着 Visual Studio "15" Preview 4 版本的发布,这些特性中的大部分将活跃起来.现在是时候来展示这些特性,你也告诉借此告诉我们你的想法! C#7.0 增加了许多新功能,并专注于数据消费,简化代码和性能的改善.或许最大的特性就是元祖和模式匹配,元祖可以很容易地拥有多个返回结果,而模型匹配可以根据数据的"形"的不同来简化代码.我们希望,将它们结合起来,从而使你的代码更加简洁高效,也可以使你更加

在低版本的vc中使用vc 10.0的新特性

/*! 在低版本的vc中使用vc 10.0的新特性 created by : andrew.wu (erpingwu@gmail.com) */ vc 10.0提供了一些新的特性,最引人注目的莫过于lambda, 但vs2010 beta内存占用之多也不得不让人心生退让. 高手 7cat 指出 "vc ide 只是一个壳" 那么如果利用 vc 10.0 编译器的新功能? 以vc9为例, 注意 Tools->Projects and Solutions->VC++ Direc

[测验]C# 3.0新特性也已经基本定稿了,各种资料层出不穷,但大家对C# 2.0的新特性有多少了解呢?测验一下。

问题描述 入门题:以下哪个特性不是C#2.0的新特性:A.::命名空间别名限定符B.运算符重载C.空值类型D.匿名方法E.迭代器语法记忆题:以下哪个关键字不是C#2.0新增的:A.yeildB.globalC.fromD.fixedE.where提高题:以下关于匿名方法的说法,哪个是错的?A.匿名方法没有方法名B.匿名方法以委托的形式存在C.匿名方法方法参数类型是自动推断的D.匿名方法返回值类型是自动推断的E.匿名方法不能直接赋值给没有方法签名的Delegate类型对象.终极题:嗯嗯,既然是终极

Struts 2.0的新特性

Struts 2.0的新特性 Struts 2.0框架中出现的许多特性旨在让Struts更容易使用: ● 改进的设计: 与Struts 1相比,Struts 2的所有类都基于接口,核心接口独立于HTTP.这些API并不依赖服务器小程序API. ● 简化的Action: Struts 2 Action类独立于框架,是简化的普通Java对象(POJO).拥有execute()方法的任何Java类都可以用做Action类. ● POJO表单: Struts 2不支持ActionForms特性.Acti