Javen-Studio 咖啡小屋

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

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  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 子句结束。这个最初的(initialfrom 子句能够跟随在(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)一个新的查询表达式。这里是这种简单的语法来阐明(illustratesinto 关键词是怎样适应(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)来履行(fulfillsLINQ模式(LINQ pattern)的任何事物。上面描述的标准查询操作符工作的方式是通过使用扩展方法(extension methods)来增加(augment IEnumerable<T> 接口。开发者可以使用(exploit)查询语法(query syntax)在任何他们希望的类型上(any type they wish),只要(as long as)他们确信(make sure)它追随(adheres toLINQ模式(LINQ pattern),而不是通过直接实现需要的方法(direct implementation of the necessary methods),或者通过像扩展方法一样添加它们(adding them as extension methods)。

 

这个LINQ项目自己开发(exploited)的扩展特性(extensibility)是通过供应(the provision of)两个LINQ式的APItwo 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 阅读(1108) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理