Javen-Studio 咖啡小屋

http://javenstudio.org - C++ Java 分布式 搜索引擎
Naven's Research Laboratory - Thinking of Life, Imagination of Future

  开发者Cpp博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  24 随笔 :: 57 文章 :: 170 评论 :: 4 Trackbacks

4.4         查询语法(Query Syntax)

C# 中现有的 foreach 语句在 .NET Framework 的 IEnumerable/IEnumerator 方法之上提供了一个声明式的语法(declarative syntax)。Foreach 语句确实是可选的(is strictly optional),但是却被证明(proven to)是一个非常方便(convenient)和流行的(popular)语言机制(language mechanism)。

 

建立在这种先例之上(Building on this precedent),查询语法(query syntax)对大多数通用的查询操作符(common query operators)来说使用一个声明式的语法(declarative syntax)来简单地查询表达式(query expressions),如 Where, Select, SelectMany, GroupBy, OrderBy, ThenBy, OrderByDescending, 和ThenByDescending。

 

让我们先看看下面这段本文开始就提到的简单的查询:

 

IEnumerable<string> expr = names 
                           .Where(s 
=> s.Length == 5) 
                           .OrderBy(s 
=> s)
                           .Select(s 
=> s.ToUpper());

 

使用查询语法我们可以重写这段原样的语句(this exact statement)如下所示:

 

IEnumerable<string> expr = from s in names 
                           where s.Length 
== 5
                           orderby s
                           select s.ToUpper();

 

就像 C# 的 foreach 语句一样,查询语法表达式(query syntax expressions)阅读起来更紧凑更容易(more compact and easier),但是却是完全随意的(completely optional)。能写进查询语法(query syntax)的每一个表达式都有一个相应的(corresponding)使用句点“.”符号(using dot notation)的(虽然是更冗长的(albeit more verbose))语法。

 

让我们开始看看一个查询表达式(query expression)的基本结构(basic structure)。C# 里每一个合成的查询表达式(syntactic query expression)都是从一个 from 子句(from clause)开始,到一个 select 或 group 子句结束。这个最初的(initial)from 子句能够跟随在(followed by)空的或多个(zero or more) from 或 where 子句后面。每个 from 子句都是一个发生器(generator)来传入(introduces)一个涉及(ranging over)一个序列(a sequence)的迭代变量(an iteration variable),而每一个 where 子句是一个过滤器(filter)来排斥(excludes)结果中条目(items from the result)。最后的 select 或 group 子句都可以加上一个 orderby 子句的前缀(be preceded by)用来指定结果集的排序(specifies an ordering for the result)。这种简单的语法(simplified grammar)对一个单个的查询表达式(a single query expression)来说如下所示:

 

from itemName in srcExpr
((from itemName 
in srcExpr) | (where predExpr))*
(orderby (keyExpr (ascending
|descending)?)+)?
((select selExpr) 
| (group selExpr by keyExpr))

 

举例来说,考察下面两段查询表达式:

 

var query1 = from p in people
             where p.Age 
> 20
             orderby p.Age descending, p.Name
             select 
new { 
                 p.Name, Senior 
= p.Age > 30, p.CanCode
             }
;

var query2 
= from p in people
             where p.Age 
> 20
             orderby p.Age descending, p.Name
             group 
new { 
                p.Name, Senior 
= p.Age > 30, p.CanCode
             }
 by p.CanCode;

 

编译器对待(treats)这些查询表达式就像如下它们用清楚的句点符号(the following explicit dot-notation)写的程序一样:

 

var query1 = people.Where(p => p.Age > 20)
                   .OrderByDescending(p 
=> p.Age)
                   .ThenBy(p 
=> p.Name)
                   .Select(p 
=> new { 
                       p.Name, 
                       Senior 
= p.Age > 30, 
                       p.CanCode
                   }
);

var query2 
= people.Where(p => p.Age > 20)
                   .OrderByDescending(p 
=> p.Age)
                   .ThenBy(p 
=> p.Name)
                   .GroupBy(p 
=> p.CanCode, 
                            p 
=> new {
                                   p.Name, 
                                   Senior 
= p.Age > 30, 
                                   p.CanCode
                   }
);

 

查询表达式(Query expressions)执行了(perform)一个基于方法名(method names)的机器翻译处理(mechanical translation)。被选择的(that is chosen)精确的查询操作符的实现(exact query operator implementation)既依靠(depends both on)被查询的变量的类型又依靠活动范围(in scope)里的扩展方法(extension methods)。

 

查询表达式展示了多么遥远的(shown so far)未来,仅仅使用了一个发生器(only used one generator)。当不止一个的发生器(generator)被使用的时候,每一个并发的发生器(each subsequent generator)在被它替代的事物的上下文(the context of its predecessor)中被赋值(evaluated)。举例来说,考察这段对我们的查询做了很下修改(slight modification)的程序:

 

var query = from s1 in names where s1.Length == 5
            from s2 
in names where s1 == s2
            select s1 
+ " " + s2;

 

当对下面的输入的数组运行时:

 

string[] names = { "Burke", "Connor", "Frank", "Everett", 
                   
"Albert", "George", "Harris", "David" }
;

 

我们将得到下面的结果:

 

Burke Burke
Frank Frank
David David

 

上面这个查询表达式用句点符号的表达式(dot notation expression)展开(expands)如下:

 

var query = names.Where(s1 => s1.Length == 5)
                 .SelectMany(s1 
=> 
                     names.Where(s2 
=> s1 == s2) 
                          .Select(s2 
=> s1 + " " + s2)
                 );

 

注意 SelectMany 的使用会导致(causes)在我们外部的结果(in the outer result)中的内部的查询表达式(the inner query expression)变得呆板(to be flattened)。

 

我们对查询表达式的简单的语法(simplified grammar)从本节开始(from earlier in this section)就忽略了(omitted)一个很有用的特性(very useful feature)。在一个并发的查询里(in a subsequent query)它是很有用的在将一个查询的结果(results of one query)视为(treat as)一个发生器(a generator)的时候。为了支持这种特性,查询表达式使用 into 关键词来在一个 select 或 group 子句之后结合(splice)一个新的查询表达式。这里是这种简单的语法来阐明(illustrates)into 关键词是怎样适应(fits in with)其余的语法的(the rest of the syntax)。

 

from itemName in srcExpr
((from itemName 
in srcExpr) | (where predExpr))*
(orderby (keyExpr (ascending
|descending)?)+)?
((select selExpr) 
| (group selExpr by keyExpr))
(
  into itemName
    ((from itemName 
in srcExpr) | (where predExpr))*
    (orderby (keyExpr (ascending
|descending)?)+)?
    ((select selExpr) 
| (group selExpr by keyExpr))
)
*

 

这个 into 关键词对后期处理(post-processing)一个 group by 子句的结果来说是特别有用的(especially useful)。例如,考查下面的程序:

 

var query = from item in names
            orderby item
            group item by item.Length into lengthGroups
            orderby lengthGroups.Key descending
            select lengthGroups;

foreach (var group in query) { 
    Console.WriteLine(
"Strings of length {0}", group.Key);

    
foreach (var val in group.Group)
        Console.WriteLine(
"  {0}", val);
}

 

这段程序输出下面的结果:

 

Strings of length 7
  Everett
Strings of length 
6
  Albert
  Connor
  George
  Harris
Strings of length 
5
  Burke
  David
  Frank

 

本章节描述的是 C# 语言是怎么实现查询表达式的,其他的语言可能选择(elect)使用清楚的语法(explicit syntax)来支持附加的查询操作符(additional query operators)。

 

需要重点注意的是(It is important to note that)查询语法(query syntax)决不是(is by no means)硬要联系上(hard-wired to)标准查询操作符(the standard query operators),它是纯净的语法特性(purely syntactic feature)可以应用于(applies to)任何通过使用适当的名字和签名(the appropriate names and signatures)实现基本方法(underlying methods)来履行(fulfills)LINQ模式(LINQ pattern)的任何事物。上面描述的标准查询操作符工作的方式是通过使用扩展方法(extension methods)来增加(augment) IEnumerable<T> 接口。开发者可以使用(exploit)查询语法(query syntax)在任何他们希望的类型上(any type they wish),只要(as long as)他们确信(make sure)它追随(adheres to)LINQ模式(LINQ pattern),而不是通过直接实现需要的方法(direct implementation of the necessary methods),或者通过像扩展方法一样添加它们(adding them as extension methods)。

 

这个LINQ项目自己开发(exploited)的扩展特性(extensibility)是通过供应(the provision of)两个LINQ式的API(two LINQ-enabled API's)提供的。其中一个名叫 DLinq,它是为基于SQL的数据访问(SQL-based data access)提供的LINQ模式的实现,另一个叫作 XLinq,它允许 LINQ 查询 XML 数据。它们两个都在下面的章节里描述。

 

 

 

 

 

待续, 错误难免,请批评指正,译者Naven 2005-10-24

posted on 2005-10-25 20:27 Javen-Studio 阅读(1214) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航:   博客园   博客园最新博文   博问   管理