原文:《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)
中国最大的web开发资源网站及技术社区,
新闻热点
疑难解答