C#3.0 Sepcification(中英文对照)

简介:       C# Version 3.0 Specification September 2005 Notice © 2005 Microsoft Corporation.
 
 
 

C#
Version 3.0 Specification
September 2005

Notice
© 2005 Microsoft Corporation. All rights reserved.
Microsoft, Windows, Visual Basic, Visual C#, and Visual C++ are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries/regions.
Other product and company names mentioned herein may be the trademarks of their respective owners.
 

Table of Contents
目录
26. Overview of C# 3.0 C# 3.0 概述............................................................................................ 5
26.1 Implicitly typed local variables   隐型局部变量 (Implicity typed local variables)...................................... 5
26.2 Extension methods 扩展方法 ............................................................................................................ 6
26.2.1 Declaring extension methods    声明扩展方法 ................................................................................ 6
26.2.2 Importing extension methods   导入扩展方法 ................................................................................ 7
26.2.3 Extension method invocations  扩展方法的调用 ........................................................................... 7
26.3 Lambda expressions           Lambda 表达式 ................................................................................................. 8
26.3.1 Lambda expression conversions     Lambda 表达式转换 ................................................................ 10
26.3.2 Type inference    类型推导 ......................................................................................................... 11
26.3.3 Overload resolution    重载决议 ................................................................................................... 13
26.4 Object and collection initializers    对象和集合的初始化器 ................................................................. 14
26.4.1 Object initializers    对象初始化器 ............................................................................................... 14
26.4.2 Collection initializers    集合初始化器 .......................................................................................... 16
26.5 Anonymous types   匿名类型 ............................................................................................................ 17
26.6 Implicitly typed arrays    隐型数组 (Implicitly typed arrays).................................................................. 18
26.7 Query expressions   查询表达式 ....................................................................................................... 19
26.7.1 Query expression translation   查询表达式的转换 ....................................................................... 20
26.7.1.1 where clauses where 子句 ................................................................................................... 21
26.7.1.2 select clauses select 子句 ................................................................................................... 21
26.7.1.3 group clauses group 子句 ..................................................................................................... 21
26.7.1.4 orderby clauses orderby 子句 .............................................................................................. 22
26.7.1.5 Multiple generators 多重产生器 (generator) ....................................................................... 22
26.7.1.6 into clauses    info 子句 .......................................................................................................... 23
26.7.2 The query expression pattern   查询表达式模式 .......................................................................... 23
26.7.3 Formal translation rules   正式的转换规则 .................................................................................. 24
26.8 Expression trees   表达式树 ............................................................................................................ 26

26. Overview of C# 3.0 (C# 3.0概述)
C# 3.0 (“C# Orcas”) introduces several language extensions that build on C# 2.0 to support the creation and use of higher order, functional style class libraries. The extensions enable construction of compositional APIs that have equal expressive power of query languages in domains such as relational databases and XML. The extensions include:
C# 3.0 (“C# 魔兽 (Orcas)”) 引入了几个构建在 C# 2.0 上的语言扩展,用来支持创建和使用更高级的函数式 (functional 或译:泛函 ) 类库。这些扩展允许 组合 (compositional)APIs 的构造,这些 APIs 关系数据库 XML 等领域中的查询语言具有同等的表达力。
·         Implicitly typed local variables, which permit the type of local variables to be inferred from the expressions used to initialize them.
·         隐型局部变量 ,允许局部变量的类型从初始化它们的表达式推导而来。
·         Extension methods, which make it possible to extend existing types and constructed types with additional methods.
·         扩展方法 ,使得使用附加 (additional) 的方法扩展已存在的类型和构造类型成为可能。
·         Lambda expressions, an evolution of anonymous methods that provides improved type inference and conversions to both delegate types and expression trees.
·         Lambda 表达式 ,是匿名方法的演进,可提供改良的类型推导和到 dalegate 类型和表达式树的 转换。
·         Object initializers, which ease construction and initialization of objects.
·         对象初始化器 ,简化了对象的构造和初始化。
·         Anonymous types, which are tuple types automatically inferred and created from object initializers.
·         匿名类型 ,是从对象初始化器自动推导和创建的元组 (tuple) 类型。
·         Implicitly typed arrays, a form of array creation and initialization that infers the element type of the array from an array initializer.
·         隐型数组 ,数组创建和初始化的形式,它从数组初始化器推导出数组的元素类型。
·         Query expressions, which provide a language integrated syntax for queries that is similar to relational and hierarchical query languages such as SQL and XQuery.
·         查询表达式 ,为类似于关系型和层次化查询语言(比如 SQL XQuery 提供一个语言集成 (intergrated) 的语法。
·         Expression trees, which permit lambda expressions to be represented as data (expression trees) instead of as code (delegates).
·         表达式树 ,允许 lambda 表达式表示为数据 ( 表达式树 ) 而不是代码 (delegate)
This document is a technical overview of those features. The document makes reference to the C# Language Specification 1.2 (§1 through §18) and the C# Language Specification 2.0 (§19 through §25), both of which are available on the C# Language Home Page ( http://msdn.microsoft.com/vcsharp/language ).
本文档是这些特征的技术概述。文档引用了 C# 语言规范 1.2 §1-§18 )和 C# 语言规范 2.0 §19-§25 ),这两个规范都在 C# 语言主页上 (http://msdn.microsoft.com/vcsharp/language)
In an implicitly typed local variable declaration, the type of the local variable being declared is inferred from the expression used to initialize the variable. When a local variable declaration specifies var as the type and no type named var is in scope, the declaration is an implicitly typed local variable declaration. For example:
在隐型局部变量声明中,正被声明的局部变量的类型从初始化这个变量的表达式推导得来。当局部变量声明指明 var 作为类型,并且该范围域 (scope) 中没有 var 名称的类型存在,这个声明就称为隐型局部声明。例如:
var i = 5;
var s = "Hello";
var d = 1.0;
var numbers = new int[] {1, 2, 3};
var orders = new Dictionary<int,Order>();
The implicitly typed local variable declarations above are precisely equivalent to the following explicitly typed declarations:
上面的隐型局部变量声明精确地等同于下面的显型 (explicitly typed) 声明:
int i = 5;
string s = "Hello";
double d = 1.0;
int[] numbers = new int[] {1, 2, 3};
Dictionary<int,Order> orders = new Dictionary<int,Order>();
A local variable declarator in an implicitly typed local variable declaration is subject to the following restrictions:
隐型局部变量声明中的局部变量声明符 (declarator) 遵从下面这些约束:
·         The declarator must include an initializer.
·         声明符必须包含初始化器。
·         The initializer must be an expression. The initializer cannot be an object or collection initializer (§26.4) by itself, but it can be a new expression that includes an object or collection initializer.
·         初始化器必须是一个表达式。初始化器不能是一个自身的对象或者集合初始化器 (26.4) ,但是它可以是包含一个对象或集合初始化器的一个 new 表达式。
·         The compile-time type of the initializer expression cannot be the null type.
·         初始化器表达式的编译期类型不可以是空 (null) 类型。
·         If the local variable declaration includes multiple declarators, the initializers must all have the same compile-time type.
·         如果局部变量声明包含了多个声明符,这些声明符必须具备同样的编译期类型。
The following are examples of incorrect implicitly typed local variable declarations:
下面是一些不正确的隐型局部变量声明的例子:
var x;              // Error, no initializer to infer type from
var y = {1, 2, 3}; // Error, collection initializer not permitted
var z = null;       // Error, null type not permitted
For reasons of backward compatibility, when a local variable declaration specifies var as the type and a type named var is in scope, the declaration refers to that type; however, a warning is generated to call attention to the ambiguity. Since a type named var violates the established convention of starting type names with an upper case letter, this situation is unlikely to occur.
因为向后兼容的原因,当局部变量声明指定 var 作为类型,而范围域中又存在叫 var 的类型,则这个声明会推导为那个叫 var 的类型;然后,会产生一个关注含糊性 (ambiguity) 的警告,因为叫 var 的类型违反了既定的类名首字母大写的约定,这个情形也未必会出现。 ( 译者:视编译器实现而定 )
The for-initializer of a for statement (§8.8.3) and the resource-acquisition of a using statement (§8.13) can be an implicitly typed local variable declaration. Likewise, the iteration variable of a foreach statement (§8.8.4) may be declared as an implicitly typed local variable, in which case the type of the iteration variable is inferred to be the element type of the collection being enumerated. In the example
for 表达式 (§8.8.3) for 初始化器 (for-initializer) using 表达式的资源获取 (resource-acquisition) 可以作为一个隐型局部变量声明。同样, foreach 表达式 (§8.8.4) 迭代变量可以声明为一个隐型局部变量,这种情况下,(隐型局部变量的)类型推导为正被枚举 (enumerated) 的集合的元素的类型。例子:
int[] numbers = { 1, 3, 5, 7, 9 };
foreach (var n in numbers) Console.WriteLine(n);
the type of n is inferred to be int , the element type of numbers .
n 的类型推导为 numbers 的元素类型 int
Extension methods are static methods that can be invoked using instance method syntax. In effect, extension methods make it possible to extend existing types and constructed types with additional methods.
扩展方法 是可以通过使用实例方法语法调用的静态方法。效果上,扩展方法使得用附加的方法扩展已存在类型和构造类型成为可能。
Note
Extension methods are less discoverable and more limited in functionality than instance methods. For those reasons, it is recommended that extension methods be used sparingly and only in situations where instance methods are not feasible or possible.
Extension members of other kinds, such as properties, events, and operators, are being considered but are currently not supported.
注意
扩展方法不容易被发现并且在功能上比实例方法更受限。由于这些原因,推荐保守地使用和仅在实例方法不可行或不可能的情况下使用。
其它种类的扩展方法,比如属性、事件和操作符,正在被考虑当中,但是当前并不被支持。
Extension methods are declared by specifying the keyword this as a modifier on the first parameter of the methods. Extension methods can only be declared in static classes. The following is an example of a static class that declares two extension methods:
扩展方法是通过指定关键字 this 修饰方法的第一个参数 而声明的。扩展方法仅可声明在静态类中。下面是声明了两个扩展方法的静态类的例子:
namespace Acme.Utilities
{
public static class Extensions
{
    public static int ToInt32(this string s) {
       return Int32.Parse(s);
    }
    public static T[] Slice<T>(this T[] source, int index, int count) {
       if (index < 0 || count < 0 || source.Length – index < count)
          throw new ArgumentException();
       T[] result = new T[count];
       Array.Copy(source, index, result, 0, count);
       return result;
    }
}
}
Extension methods have all the capabilities of regular static methods. In addition, once imported, extension methods can be invoked using instance method syntax.
扩展方法具备所有常规静态方法的所有能力。另外,一旦被导入,扩展方法可以使用实例方法语法调用之。
Extension methods are imported through using-namespace-directives (§9.3.2). In addition to importing the types contained in a namespace, a using-namespace-directive imports all extension methods in all static classes in the namespace. In effect, imported extension methods appear as additional methods on the types that are given by their first parameter and have lower precedence than regular instance methods. For example, when the Acme.Utilities namespace from the example above is imported with the using-namespace-directive
扩展方法用using-namespace-directive s (§9.3.2) 导入。除了导入包含在名字空间中的类型外, using-namespace-directives 也导入了名字空间中所有静态类中的所有扩展方法。实际上,被导入的扩展方法作为被修饰的第一个参数类型上的附加方法出现,并且相比常规实例方法具有较低的优先权。比如,当使用 using-namespace-directive 导入 上个例子中 Acme.Utilities 名字空间:
using Acme.Utilities;
it becomes possible to invoke the extension methods in the static class Extensions using instance method syntax:
它使得可以在静态类 Extension 上使用实例方法语法调用扩展方法:
 
string s = "1234";
int i = s.ToInt32();               // Same as Extensions.ToInt32(s)
int[] digits = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] a = digits.Slice(4, 3);      // Same as Extensions.Slice(digits, 4, 3)
The detailed rules for extension method invocation are described in the following. In a method invocation (§7.5.5.1) of one of the forms
扩展方法调用的详细规则表述如下。以如下调用形式之一:
expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )
if the normal processing of the invocation finds no applicable instance methods (specifically, if the set of candidate methods for the invocation is empty), an attempt is made to process the construct as an extension method invocation. The method invocation is first rewritten to one of the following, respectively:
如果调用的正常处理过程发现没有适用的实例方法(特别地,如果这个调用的候选方法集是空的),就会试图处理扩展方法调用的构造。方法调用会首先被分别重写称如下之一:
identifier ( expr )
identifier ( expr , args )
identifier < typeargs > ( expr )
identifier < typeargs > ( expr , args )
The rewritten form is then processed as a static method invocation, except for the way in which identifier is resolved: Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to process the rewritten method invocation with a method group consisting of all accessible extension methods with the name given by identifier imported by the namespace declaration’s using-namespace-directives. The first method group that yields a non-empty set of candidate methods is the one chosen for the rewritten method invocation. If all attempts yield empty sets of candidate methods, a compile-time error occurs.
重写后的形式然后被作为静态方法调用处理,除非标识符 identifier 决议为:以最靠近的封闭名字空间声明开始,以每个封闭名字空间声明继续,并以包含的编译单元结束,持续地试图用组成所有可访问的,由 using-namespace-directives导入的,指明为 identifier名字的扩展方法处理重写的方法调用。第一个产生非空候选方法集的方法组(method group)就成为被选中的重写的方法调用。如果所有的努力都只产生空的候选集,则发生编译期错误。
The preceeding rules mean that instance methods take precedence over extension methods, and extension methods imported in inner namespace declarations take precedence over extension methods imported in outer namespace declarations. For example:
前面的规则标表明实例方法优先于扩展方法,并且导入进内层名字空间中的扩展方法优先于导入进外层名字空间中的扩展方法。例如:
using N1;
namespace N1
{
public static class E
{
    public static void F(this object obj, int i) { }
    public static void F(this object obj, string s) { }
}
}
class A { }
class B
{
public void F(int i) { }
}
class C
{
public void F(object obj) { }
}
class X
{
static void Test(A a, B b, C c) {
    a.F(1);            // E.F(object, int)
    a.F("hello");      // E.F(object, string)
   b.F(1);            // B.F(int)
    b.F("hello");      // E.F(object, string)
    c.F(1);            // C.F(object)
    c.F("hello");      // C.F(object)
}
}
In the example, B ’s method takes precedence over the first extension method, and C ’s method takes precedence over both extension methods.
例子中, B 的方法优先于第一个扩展方法, C 的方法优先于两个扩展方法。
26.3 Lambda expressions Lambda表达式
C# 2.0 introduces anonymous methods, which allow code blocks to be written “in-line” where delegate values are expected. While anonymous methods provide much of the expressive power of functional programming languages, the anonymous method syntax is rather verbose and imperative in nature. Lambda expressions provide a more concise, functional syntax for writing anonymous methods.
C# 2.0 引入了匿名方法,它允许在 delegate (delegate value) ( 译者 :delegate 对象 ) 被需要的地方以内联 (in-line) 方式写一个代码块。当匿名方法提供了大量函数式编程语言 ( 或泛函编程 )(functional programming) 的表达力时,实质上,匿名方法的语法是相当烦琐和带有强制性的。 Lambda 表达式提供了一个更加简练的函数式语法来写匿名方法。
A lambda expression is written as a parameter list, followed by the => token, followed by an expression or a statement block.
Lambda 表达式写成一个后面紧跟  => 标记的参数列表, => 之后是一个表达式或表语句块。
expression:
assignment
non-assignment-expression
non-assignment-expression:
conditional-expression
lambda-expression
query-expression
lambda-expression:
(    lambda-parameter-listopt   )   =>   lambda-expression-body
implicitly-typed-lambda-parameter  
=>   lambda-expression-body
lambda-parameter-list:
explicitly-typed-lambda-parameter-list
implicitly-typed-lambda-parameter-list
explicitly-typed-lambda-parameter-list
explicitly-typed-lambda-parameter
explicitly-typed-lambda-parameter-list   ,   explicitly-typed-lambda-parameter
explicitly-typed-lambda-parameter:
parameter-modifieropt   type   identifier
implicitly-typed-lambda-parameter-list
implicitly-typed-lambda-parameter
implicitly-typed-lambda-parameter-list   ,   implicitly-typed-lambda-parameter
implicitly-typed-lambda-parameter:
identifier
lambda-expression-body:
expression
block
The parameters of a lambda expression can be explicitly or implicitly typed. In an explicitly typed parameter list, the type of each parameter is explicitly stated. In an implicitly typed parameter list, the types of the parameters are inferred from the context in which the lambda expression occurs—specifically, when the lambda expression is converted to a compatible delegate type, that delegate type provides the parameter types (§26.3.1).
Lambda 表达式的参数可以是显型和隐型的。在显型参数列表中,每个参数的类型是显式指定的。在隐型参数列表中,参数的类型由 lambda 表达式出现的语境推导——特定地,当 lambda 表达式被转型到一个兼容的 delegate 类型时, delegate 类型提供参数的类型 (§26.3.1)
In a lambda expression with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. In other words, a lambda expression of the form
在有单一的隐型参数的 lambda 表达式中,圆括号可以从参数列表中省略。换句话说,如下形式的 lambda 表达式
( param ) => expr
can be abbreviated to
可以被简写成
param => expr
Some examples of lambda expressions follow below:
下面是一些 lambda 表达式的例子:
x => x + 1                   // Implicitly typed, expression body
x => { return x + 1; }       // Implicitly typed, statement body
(int x) => x + 1             // Explicitly typed, expression body
(int x) => { return x + 1; } // Explicitly typed, statement body
(x, y) => x * y              // Multiple parameters
() => Console.WriteLine()    // No parameters
In general, the specification of anonymous methods, provided in §21 of the C# 2.0 Specification, also applies to lambda expressions. Lambda expressions are a functional superset of anonymous methods, providing the following additional functionality:
通常, C# 2.0 规范 §21 中提供的匿名方法规范,也应用上了 lambda 表达式。 Lambda 表达式是匿名方法的泛函超集,它提供了如下附加功能:
·         Lambda expressions permit parameter types to be omitted and inferred whereas anonymous methods require parameter types to be explicitly stated.
·         Lambda 表达式允许参数类型被省略掉和被推导,尽管匿名方法要求显式指定参数类型。
·         The body of a lambda expression can be an expression or a statement block whereas the body of an anonymous method can only be a statement block.
·         Lambda 表达式体可以是一个表达式或者语句块,尽管匿名方法体可以是一个语句块。
·         Lambda expressions passed as arguments participate in type argument inference (§26.3.2) and in method overload resolution (§26.3.3).
·         Lambda 表达式作为参数传递参与类型参数推导 (§26.3.2) 和重载决议。
·         Lambda expressions with an expression body can be converted to expression trees (§26.8).
·         带有表达式体的 Lambda 表达式可以被转换成表达式树 (§26.8)
Note
The PDC 2005 Technology Preview compiler does not support lambda expressions with a statement block body. In cases where a statement block body is needed, the C# 2.0 anonymous method syntax must be used.
注意
PDC 2005技术预览编译器不支持带有语句体的lambda表达式。在需要语句体的情况下,必须使用C# 2.0匿名方法语法。
26.3.1 Lambda expression conversions Lambda表达式转换
Similar to an anonymous-method-expression, a lambda-expression is classified as a value with special conversion rules. The value does not have a type but can be implicitly converted to a compatible delegate type. Specifically, a delegate type D is compatible with a lambda-expression L provided:
与匿名方法表达式 (anonymous-method-expression) 类似, lambda 表达式是用特殊转换规则作为值 (value) 类型分类的。这个值 (value) 没有类型,但是可以隐式转型至一个兼容的 delegate 类型。特别地, delegate 类型 D lambda 表达式 L 兼容的,如果:
·         D and L have the same number of parameters.
·         D L 有相同数目的参数。
·         If L has an explicitly typed parameter list, each parameter in D has the same type and modifiers as the corresponding parameter in L .
·         如果 L 有显型参数列表, D 中的每个参数有着与相应的 L 中的参数相同的类型和修饰符。
·         If L has an implicitly typed parameter list, D has no ref or out parameters.
·         如果 L 有隐型参数列表, D 不可有 ref out 参数。
·         If D has a void return type and the body of L is an expression, when each parameter of L is given the type of the corresponding parameter in D , the body of L is a valid expression that would be permitted as a statement-expression (§8.6).
·         如果 D void 返回类型,并且 L 的体 (body) 是一个表达式,当 L 的每个参数被给定为对应的 D 中参数 的类型时, L 的体是一个允许作为语句 - 表达式 (statement-expression(§8.6)) 的有效表达式
·         If D has a void return type and the body of L is a statement block, when each parameter of L is given the type of the corresponding parameter in D , the body of L is a valid statement block in which no return statement specifies an expression.
·         如果 D void 返回类型并且 L 的体是语句块,当 L 的每个参数类型是被给定为相应的 D 参数的类型时, L 的体是一个没有返回语句的有效语句块。
·         If D has a non-void return type and the body of L is an expression, when each parameter of L is given the type of the corresponding parameter in D , the body of L is a valid expression that is implicitly convertible to the return type of D .
·         如果 D non-void 返回值并且 L 的体是一个表达式,当 L 的每个参数类型是被给定的相应于 D 参数的类型时, L 的体是一个可以隐式转换到 D 返回类型的有效表达式。
·         If D has a non-void return type and the body of L is a statement block, when each parameter of L is given the type of the corresponding parameter in D , the body of L is a valid statement block with a non-reachable end point in which each return statement specifies an expression that is implicitly convertible to the return type of D .
·         如果 D non-void 返回值并且 L 的体是一个语句块,当 L 的每个参数类型是被给定的相应于 D 参数的类型时, L 的体是一个有效的语句块,语句块中有不可到达 (non-reachable) 的终点 (end point)( 译者:是否应该为“没有不可到达的终点” ) ,且每个终点的返回语句指明一个可以隐式转换到 D 返回类型的 表达式。
The examples that follow use a generic delegate type Func<A,R> which represents a function taking an argument of type A and returning a value of type R :
下面的例子使用泛型 delegagte 类型 Func<A,R> 表示一个带有参数类型 A 和返回类型 R 的函数
delegate R Func<A,R>(A arg);
In the assignments
赋值如下:
Func<int,int> f1 = x => x + 1;        // Ok
Func<int,double> f2 = x => x + 1;     // Ok
Func<double,int> f3 = x => x + 1;     // Error
the parameter and return types of each lambda expression are determined from the type of the variable to which the lambda expression is assigned. The first assignment successfully converts the lambda expression to the delegate type Func<int,int> because, when x is given type int , x + 1 is a valid expression that is implicitly convertible to type int . Likewise, the second assignment successfully converts the lambda expression to the delegate type Func<int,double> because the result of x + 1 (of type int ) is implicitly convertible to type double . However, the third assignment is a compile-time error because, when x is given type double , the result of x + 1 (of type double ) is not implicitly convertible to type int .
每个 Lambda 表达式的参数和返回类型决定于 lambda 表达式被赋值的变量的类型。第一个赋值成功地转换 lambda 表达式到 delegate 类型 Func<int,int> ,是因为当 x int 型, x+1 是一个有效的表达式并可以隐式地转换到类型 int 。同样第二个赋值成功地转换 lambda 表达式到 delegate 类型 Func<int,double> ,是因为 x+1 的返回值(类型 int )是隐式转换成 double 的。然而第三个赋值有编译期错误,因为当 x double x+1 double ,不能够隐式转变到类型 int
26.3.2 Type inference类型推导
When a generic method is called without specifying type arguments, a type inference process attempts to infer type arguments for the call. Lambda expressions passed as arguments to the generic method participate in this type inference process.
当泛型方法被调用而不指明类型参数时,参数推导过程试图从调用中推导出类型参数。 Lambda 表达式参数传递给泛型方法参与这个类型推导过程。
As described in §20.6.4, type inference first occurs independently for each argument. In this initial phase, nothing is inferred from arguments that are lambda expressions. However, following the initial phase, additional inferences are made from lambda expressions using an iterative process. Specifically, inferences are made as long as one or more arguments exist for which all of the following are true:
如同 §20.6.4 中表述的那样,类型推导首先为每个参数独立的发生。在初始阶段,不能从 lambda 表达式参数推导出任何东西。然而,初始阶段之后,产生了使用迭代过程的额外的推导。特别地,只要有一个或多个满足如下条件为真的参数存在,推导将会产生:
·         The argument is a lambda expression, in the following called L , from which no inferences have yet been made.
·         参数是 lambda 表达式,下面称为 L ,从中,尚无推导。
·         The corresponding parameter’s type, in the following called P , is a delegate type with a return type that involves one or more method type parameters.
·         相应的参数类型,下面称为 P ,是有返回类型的含有一个或多个方法类型参数的 delegate
·         P and L have the same number of parameters, and each parameter in P has the same modifiers as the corresponding parameter in L , or no modifiers if L has an implicitly typed parameter list.
·         P L 拥有相同数目的参数,并且 P 中的每个参数与 L 中相应的参数具有相同的修饰符,或者如果 L 有隐型参数列表时,没有修饰符。
·         P ’s parameter types involve no method type parameters or involve only method type parameters for which a consistent set of inferences have already been made.
·         P 的参数类型不包含方法类型参数或者包含仅仅一个方法类型参数,对这个参数已经产生一个相容的推导集。
·         If L has an explicitly typed parameter list, when inferred types are substituted for method type parameters in P , each parameter in P has the same type as the the corresponding parameter in L .
·         如果 L 有一个显型参数列表,当推导出的类型对于 P 中的方法类型参数是可替换的时候, P 中的每个参数拥有与 L 中对应的参数相同的类型。
·         If L has an implicitly typed parameter list, when inferred types are substituted for method type parameters in P and the resulting parameter types are given to the parameters of L , the body of L is a valid expression or statement block.
·         如果 L 有一个隐型参数列表,当推导出的类型对于 P 中的方法类型参数是可替代的,并且返回参数类型被给予 L 的参数, L 的体是一个有效表达式或语句块。
·         A return type can be inferred for L , as described below.
·         返回类型可以为 L 推导出来,描述如下:
For each such argument, inferences are made from that argument by relating the return type of P with the inferred return type of L and the new inferences are added to the accumulated set of inferences. This process is repeated until no further inferences can be made.
对每一个这样的参数,将会通过关联 P 的返回类型和 L 的推导返回类型做出推论,并且新的推论被加入进累积的推论集。这个过程将重复进行,直到没有更进一步的推论产生为止。
For purposes of type inference and overload resolution, the inferred return type of a lambda expression L is determined as follows:
因为类型推导和重载决议的原因, lambda 表达式 L 推导出的类型决定于下面:
·         If the body of L is an expression, the type of that expression is the inferred return type of L .
·         如果 L 的体是一个表达式,表达式的类型就是推导出的 L 的返回类型。
·         If the body of L is a statement block, if the set formed by the types of the expressions in the block’s return statements contains exactly one type to which each type in the set is implicitly convertible, and if that type is not the null type, then that type is the inferred return type of L .
·         如果 L 的体是一个语句块,如果由语句块中 return 语句表达式的类型 形成的集合 (set) 正好包含一个集合中每个类型都可隐式转换成的类型,那么这个类型就是推导出的 L 的返回类型。 ( 译者:如果有个集合 {int, byte, double} ,则 double 满足要求 )
·         Otherwise, a return type cannot be inferred for L .
·         此外,返回类型不能为 L 推导出来。
As an example of type inference involving lambda expressions, consider the Select extension method declared in the System.Query.Sequence class:
作为一个包含 lambda 表达式的类型推导的例子,考虑声明于 System.Query.Sequence 类中的 Select 扩展方法:
namespace System.Query
{
public static class Sequence
{
   public static IEnumerable<S> Select<T,S>(
       this IEnumerable<T> source,
      Func<T,S> selector)
   {
      foreach (T element in source) yield return selector(element);
   }
}
}
Assuming the System.Query namespace was imported with a using clause, and given a class Customer with a Name property of type string , the Select method can be used to select the names of a list of customers:
假定 System.Query 名字空间使用 using 子句导入,并且给出一个类 Customer ,带有类型为 string 的属性 Name, Select 方法可用作选择一列 (list of )customers 名字
List<Customer> customers = GetCustomerList();
IEnumerable<string> names = customers.Select(c => c.Name);
The extension method invocation (§26.2.3) of Select is processed by rewriting the invocation to a static method invocation:
Select 扩展方法调用通过重写静态方法调用处理:
IEnumerable<string> names = Sequence.Select(customers, c => c.Name);
Since type arguments were not explicitly specified, type inference is used to infer the type arguments. First, the customers argument is related to the source parameter, inferring T to be Customer . Then, using the lambda expression type inference process described above, c is given type Customer , and the expression c.Name is related to the return type of the selector parameter, inferring S to be string . Thus, the invocation is equivalent to
因为类型参数未被显式指明,将会使用类型推导来推导类型参数。首先 customers 参数被关联到 source 参数,推导 T Customer 。然后使用前面描述的 lambda 表达式类型推导过程 , c 是给定类型 Customer ,而表达式 c.Name 被关联到 selector 参数的返回类型上,推导 s string ,这样,调用就等价于
Sequence.Select<Customer,string>(customers, (Customer c) => c.Name)
and the result is of type IEnumerable<string> .
返回类型是 IEnumerable<string>
The following example demonstrates how lambda expression type inference allows type information to “flow” between arguments in a generic method invocation. Given the method
下面的例子示范了 lambda 表达式类型推导是如何允许类型信息在泛型函数调用的参数之间“流动”的。给出方法
 
static Z F<X,Y,Z>(X value, Func<X,Y> f1, Func<Y,Z> f2) {
return f2(f1(value));
}
type inference for the invocation
调用的类型推导
double seconds = F("1:15:30", s => TimeSpan.Parse(s), t => t.TotalSeconds);
proceeds as follows: First, the argument "1:15:30" is related to the value parameter, inferring X to be string . Then, the parameter of the first lambda expression, s , is given the inferred type string , and the expression TimeSpan.Parse(s) is related to the return type of f1 , inferring Y to be System.TimeSpan . Finally, the parameter of the second lambda expression, t , is given the inferred type System.TimeSpan , and the expression t.TotalSeconds is related to the return type of f2 , inferring Z to be double . Thus, the result of the invocation is of type double .
处理过程如下:首先参数 ”1:15:30” 被关联到值参数,推导 X string 。然后第一个 lambda 表达式的参数 s 是给定推导类型 string ,并且表达式 TimeSpan.Parse(s) 被关联到 f1 的返回类型上,推导 Y System.TimeSpan 。最后第二个 lambda 表达式的参数 t ,是给定为推导类型 System.TimeSpan ,表达式 t.ToTalSeconds 被关联到 f2 的返回类型上,推导 Z double 。这样,调用的返回类型就是 double
Lambda expressions in an argument list affect overload resolution in certain situations.
参数列表中的 Lambda 表达式在某些条件下影响重载决议。
The following rule augments §7.4.2.3: Given a lambda expression L for which an inferred return type (§26.3.2) exists, an implicit conversion of L to a delegate type D1 is a better conversion than an implicit conversion of L to a delegate type D2 if D1 and D2 have identical parameter lists and the implicit conversion from L’s inferred return type to D1’s return type is a better conversion than the implicit conversion from L’s inferred return type to D2’s return type. If these conditions are not true, neither conversion is better.
下面的规则要增加进 §7.4.2.3 :给定一个 lambda 表达式 L ,为其推导出的返回类型存在,如果 delegate 类型 D1 D2 具有相同的参数列表,从 L D1的隐式转型比从LD2的隐式转型更好;并且从L推导出的返回类型D1返回类型的隐式转型比从L推导出的返回类型到D2返回类型的隐式转型更好。如果这些条件不为真,两者都不行。
The following example illustrates the effect of this rule.
下面的例子例示了这个规则的效果。
class ItemList<T>: List<T>
{
public int Sum<T>(Func<T,int> selector) {
    int sum = 0;
    foreach (T item in this) sum += selector(item);
    return sum;
}
public double Sum<T>(Func<T,double> selector) {
    double sum = 0;
    foreach (T item in this) sum += selector(item);
    return sum;
}
}
The ItemList<T> class has two Sum methods. Each takes a selector argument, which extracts the value to sum over from a list item. The extracted value can be either an int or a double and the resulting sum is likewise either an int or a double .
ItemList<T> 类有两个 Sum 方法。每个方法都有一个 selector 参数,方法从列表项中提取值累加进 sum 。提取的值可以是 int double 型,返回 sum 同样可以是 int double 型。
The Sum methods could for example be used to compute sums from a list of detail lines in an order.
Sum 方法可以作为例子用于从 detail 列表中依次计算和。
class Detail
{
public int UnitCount;
public double UnitPrice;
...
}
void ComputeSums() {
ItemList<Detail> orderDetails = GetOrderDetails(...);
int totalUnits = orderDetails.Sum(d => d.UnitCount);
double orderTotal = orderDetails.Sum(d => d.UnitPrice * d.UnitCount);
...
}
In the first invocation of orderDetails.Sum , both Sum methods are applicable because the lambda expression d => d.UnitCount is compatible with both Func<Detail,int> and Func<Detail,double> . However, overload resolution picks the first Sum method because the conversion to Func<Detail,int> is better than the conversion to Func<Detail,double> .
orderDetails.Sum 首次调用中,两个 Sum 方法都适用,这是因为 lambda 表达式 d=>d.UnitCount 兼容于 Func<Detail,int> Func<Detail,double> 这两者。然而,重载决议选择了第一个 Sum 方法,这是因为转换至 Func<Detail,in> 好于转换至 Func<Detail,double>
In the second invocation of orderDetails.Sum , only the second Sum method is applicable because the lambda expression d => d.UnitPrice * d.UnitCount produces a value of type double . Thus, overload resolution picks the second Sum method for that invocation
orderDetails.Sum 的第二次调用中,仅仅第二个 Sum 方法适用,这是因为 lambda 表达式 d=>d.UnitPrice*d.UnitCount 产生的类型是 double 。因此重载决议为此调用选择了第二个方法。
26.4 Object and collection initializers对象和集合初始化器
An object creation expression (§7.5.10.1) may include an object or collection initializer which initializes the members of the newly created object or the elements of the newly created collection.
对象创建表达式 (§7.5.10.1) 可以包含一个对象或集合初始化器,用于初始化新创建的对象的成员或新创建的集合的元素。
object-creation-expression:
new    type   (   argument-listopt   )   object-or-collection-initializeropt
new   type   object-or-collection-initializer
object-or-collection-initializer:
object-initializer
collection-initializer
An object creation expression can omit the constructor argument list and enclosing parentheses provided it includes an object or collection initializer. Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.
对象创建表达式可以省略构造函数 ( 译者:或译“构造器” )(constructor) 的参数列表和封闭的圆括号,而提供给它一个对象或集合初始化器。省略构造函数参数列表和封闭的圆括号等价于指定一个空参数列表。
Execution of an object creation expression that includes an object or collection initializer consists of first invoking the instance constructor and then performing the member or element initializations specified by the object or collection initializer.
包含对象或集合初始化器的对象创建表达式的执行包含首先调用实例构造函数,然后执行由对象或集合初始化器指定的成员或元素初始化动作。
It is not possible for an object or collection initializer to refer to the object instance being initialized.
对象或集合初始化器不能引用正被实例化的对象实例。
26.4.1 Object initializers对象初始化器
An object initializer specifies values for one or more fields or properties of an object.
对象初始化器指定一个或多个对象的域或属性的 值。
object-initializer:
{    member-initializer-listopt   }
{   member-initializer-list   ,   }
member-initializer-list:
member-initializer
member-initializer-list   ,   member-initializer
member-initializer:
identifier   =   initializer-value
initializer-value:
expression
object-or-collection-initializer
An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas. Each member initializer must name an accessible field or property of the object being initialized, followed by an equals sign and an expression or an object or collection initializer. It is an error for an object initializer to include more than one member initializer for the same field or property.
对象初始化器由一系列成员初始化器组成,封闭于 { } 标记内并且由逗号间隔。每个成员初始化器必须指出正被初始化的对象的域或属性的名字,后面是等号 ”=”   表达式或者对象或集合的初始化器
A member initializer that specifies an expression after the equals sign is processed in the same way as an assignment (§7.13.1) to the field or property.
在等号后面指定表达式的成员初始化器作为与对域或属性赋值同样的方式处理。
A member initializer that specifes an object initializer after the equals sign is an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the object initializer are treated as assignments to members of the field or property. A property of a value type cannot be initialized using this construct.
在等号后指定一个对象初始化器的 成员初始化器是对内嵌对象的初始化。对象初始化器中的赋值作为域或属性成员的赋值对待,而不是给域或属性赋予新值。值类型的属性不可用这种构造方式初始化
A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Instead of assigning a new collection to the field or property, the elements given in the initializer are added to the collection referenced by the field or property. The field or property must be of a collection type that satisfies the requirements specified in §26.4.2.
在等号后指定集合初始化器的 成员初始化器是对内嵌集合的初始化。初始化器中给定的元素被加进域或属性引用的集合中,而不是给域或属性赋予新的集合。域或属性必须是满足 §26.4.2 中指定要求的集合类型。
The following class represents a point with two coordinates:
下面的类要求一个有两个坐标的 point
 
public class Point
{
int x, y;
public int X { get { return x; } set { x = value; } }
public int Y { get { return y; } set { y = value; } }
}
An instance of Point can be created an initialized as follows:
Point 的实例可以被创建和实例化如下:
var a = new Point { X = 0, Y = 1 };
which has the same effect as
它等效于
var a = new Point();
a.X = 0;
a.Y = 1;
The following class represents a rectangle created from two points:
下面的这个类表示由两个 points 构成的 rectangle
public class Rectangle
{
Point p1, p2;
public Point P1 { get { return p1; } set { p1 = value; } }
public Point P2 { get { return p2; } set { p2 = value; } }
}
An instance of Rectangle can be created and initialized as follows:
Rectangle 的实例可以被创建和初始化如下:
var r = new Rectangle {
P1 = new Point { X = 0, Y = 1 },
P2 = new Point { X = 2, Y = 3 }
};
which has the same effect as
它等效于
var r = new Rectangle();
var __p1 = new Point();
__p1.X = 0;
__p1.Y = 1;
r.P1 = __p1;
var __p2 = new Point();
__p2.X = 2;
__p2.Y = 3;
r.P2 = __p2;
where __p1 and __p2 are temporary variables that are otherwise invisible and inaccessible.
这里 __p1 __p2 是临时变量且是不可见和不可访问的。
If Rectangle’s constructor allocates the two embedded Point instances
如果 Rectangle 的构造函数分配了两个内嵌的 Point 的实例
public class Rectangle
{
Point p1 = new Point();
Point p2 = new Point();
public Point P1 { get { return p1; } }
public Point P2 { get { return p2; } }
}
the following construct can be used to initialize the embedded Point instances instead of assigning new instances:
下面的构造可被用于初始化内嵌的 Point 实例,而不是赋予新的实例值。
var r = new Rectangle {
P1 = { X = 0, Y = 1 },
P2 = { X = 2, Y = 3 }
};
which has the same effect as
它等效于
var r = new Rectangle();
r.P1.X = 0;
r.P1.Y = 1;
r.P2.X = 2;
r.P2.Y = 3;
26.4.2 Collection initializers集合初始化器
A collection initializer specifies the elements of a collection.
集合初始化器指定集合的元素。
collection-initializer:
{    element-initializer-listopt   }
{   element-initializer-list   ,   }
element-initializer-list:
element-initializer
element-initializer-list   ,   element-initializer
element-initializer:
non-assignment-expression
A collection initializer consists of a sequence of element initializers, enclosed by { and } tokens and separated by commas. Each element initializer specifies an element to be added to the collection object being initialized. To avoid ambiguity with member initializers, element initializers cannot be assignment expressions. The non-assignment-expression production is defined in §26.3.
集合初始化器由一系列元素初始化器组成,封闭进 { } 标记内,以逗号间隔。每个元素初始化器指定一个将被加进正被初始化的集合对象中的元素。
The following is an example of an object creation expression that includes a collection initializer:
下面是对象创建表达式的例子,包含有一个集合初始化器:
List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
The collection object to which a collection initializer is applied must be of a type that implements System.Collections.Generic.ICollection<T> for exactly one T . Furthermore, an implicit conversion (§6.1) must exist from the type of each element initializer to T . A compile-time error occurs if these requirements are not satisfied. A collection initializer invokes the ICollection<T>.Add(T) method for each specified element in order.
被应用了集合初始化器的 集合对象必须是实现了正好一个类型 T System.Collections.Generic.IConlection<T> 类型。此外必须存在从每个元素类型到 T 类型的隐式转型。如果这些条件都不满足,就产生编译期错误。集合初始化器对每个指定元素依次调用 ICollection<T>.Add(T) 方法。
The following class represents a contact with a name and a list of phone numbers:
下面的类表示一个名字和电话号码列表的 contact
public class Contact
{
string name;
List<string> phoneNumbers = new List<string>();
public string Name { get { return name; } set { name = value; } }
public List<string> PhoneNumbers { get { return phoneNumbers; } }
}
A List<Contact> can be created and initialized as follows:
List<Contact> 可以被创建和实例化如下:
var contacts = new List<Contact> {
new Contact {
    Name = "Chris Smith",
    PhoneNumbers = { "206-555-0101", "425-882-8080" }
},
new Contact {
    Name = "Bob Harris",
    PhoneNumbers = { "650-555-0199" }
}
};
which has the same effect as
它等效于:
var contacts = new List<Contact>();
var __c1 = new Contact();
__c1.Name = "Chris Smith";
__c1.PhoneNumbers.Add("206-555-0101");
__c1.PhoneNumbers.Add("425-882-8080");
contacts.Add(__c1);
var __c2 = new Contact();
__c2.Name = "Bob Harris";
__c2.PhoneNumbers.Add("650-555-0199");
contacts.Add(__c2);
where __c1 and __c2 are temporary variables that are otherwise invisible and inaccessible.
这里 __c1 __c2 是临时变量,不可见,也不可访问。
26.5 Anonymous types匿名类型
C# 3.0 permits the new operator to be used with an anonymous object initializer to create an object of an anonymous type.
C# 3.0 允许 new 操作符与匿名对象初始化器联用来创建一个匿名类型的对象。
primary-no-array-creation-expression:

anonymous-object-creation-expression
anonymous-object-creation-expression:
new    anonymous-object-initializer
anonymous-object-initializer:
{    member-declarator-listopt   }
{   member-declarator-list   ,   }
member-declarator-list:
member-declarator
member-declarator-list   ,   member-declarator
member-declarator:
simple-name
member-access
identifier   =   expression
An anonymous object initializer declares an anonymous type and returns an instance of that type. An anonymous type is a nameless class type that inherits directly from object . The members of an anonymous type are a sequence of read/write properties inferred from the object initializer(s) used to create instances of the type. Specifically, an anonymous object initializer of the form
匿名对象初始化器声明一个匿名类型并返回这个类型的实例。一个匿名类型是一个无名类 (nameless class) (译者:参考 jjhou 先生的翻译“具名 (named) ”),它直接继承自 Object 。匿名类型的成员是一系列推导自用于创建这个类型实例的对象初始化器的 / 写属性。特别地,匿名对象初始化器具有如下形式:
new { p1 = e1 , p2 = e2 , pn = en }
declares an anonymous type of the form
它声明了一个如下形式的匿名类型
class __Anonymous1
{
private
T1 f1 ;
private
T2 f2 ;

private Tn fn ;
public T1 p1 { get { return f1 ; } set { f1 = value ; } }
public
T2 p2 { get { return f2 ; } set { f2 = value ; } }

public T1 p1 { get { return f1 ; } set { f1 = value ; } }
}
where each Tx is the type of the corresponding expression ex. It is a compile-time error for an expression in an anonymous object initializer to be of the null type.
这里每个 Tx 是对应表达式 ex 的类型。 匿名对象初始化器中的表达式是 null 类型是一个编译期错误。
The name of an anonymous type is automatically generated by the compiler and cannot be referenced in program text.
匿名类型的名字是由编译器自动产生的,在程序正文中不可被引用。
Within the same program, two anonymous object initializers that specify a sequence of properties of the same names and types in the same order will produce instances of the same anonymous type. (This definition includes the order of the properties because it is observable and material in certain circumstances, such as reflection.)
在同样的程序中,以相同顺序指定了一系列相同名字和类型的两个匿名对象初始化器将会产生相同匿名类型的实例。(这个定义包含了属性的次序,是因为它在某些环境中这是可观测和重要的,比如 reflection
In the example
例子
var p1 = new { Name = "Lawnmower", Price = 495.00 };
var p2 = new { Name = "Shovel", Price = 26.95 };
p1 = p2;
the assignment on the last line is permitted because p1 and p2 are of the same anonymous type.
最后一行的赋值是可行的,因为 p1 p2 具有相同的匿名类型。
A member declarator can be abbreviated to a simple name (§7.5.2) or a member access (§7.5.4). This is called a projection initializer and is shorthand for a declaration of and assignment to a property with the same name. Specifically, member declarators of the forms
成员声明符可以缩写成简单的名字 (§7.5.2) 或一个成员访问 (§7.5.4) 。这称为投射初始化器 (projection initializer) ,是具备相同名字属性声明和赋值的速记方式。
identifier                                                   expr . identifier
are precisely equivalent to the following, respectively:
分别等价于下面:
identifer = identifier               identifier = expr . identifier
Thus, in a projection initializer the identifier selects both the value and the field or property to which the value is assigned. Intuitively, a projection initializer projects not just a value, but also the name of the value.
因此,在投射初始化器中, identifier 选择了被赋予值的值和域或属性。直观上,投射初始化器不仅投射值,也投射值的名字。
26.6 Implicitly typed arrays隐型数组(Implicitly typed arrarys
The syntax of array creation expressions (§7.5.10.2) is extended to support implicitly typed array creation expressions:
扩展 数组创建表达式 (§7.5.10.2) 的语法用以支持隐型数组创建表达式:
array-creation-expression:

new    [    ]   array-initializer
In an implicitly typed array creation expression, the type of the array instance is inferred from the elements specified in the array initializer. Specifically, the set formed by the types of the expressions in the array initializer must contain exactly one type to which each type in the set is implicitly convertible, and if that type is not the null type, an array of that type is created. If exactly one type cannot be inferred, or if the inferred type is the null type, a compile-time error occurs.
在隐型数组创建表达式中,数组实例的类型推导自数组初始化器中元素的类型。特别地,数组初始化器中表达式类型形成的类型集合 (set) ,必须包含一个这样的类型,其中每个类型都可隐式转型成它,并且这个类型不是 null 类型,如此,这个类型的数组就被创建了。如果不能推导出一个准确的类型,或者推导出的类型是空 null 类型,编译器错误就会出现。
The following are examples of implicitly typed array creation expressions:
下面是隐型数组创建表达式的例子:
var a = new[] { 1, 10, 100, 1000 };             // int[]
var b = new[] { 1, 1.5, 2, 2.5 };           // double[]
var c = new[] { "hello", null, "world” };   // string[]
var d = new[] { 1, "one", 2, "two" };       // Error
The last expression causes a compile-time error because neither int nor string is implicitly convertible to the other. An explicitly typed array creation expression must be used in this case, for example specifying the type to be object[] . Alternatively, one of the elements can be cast to a common base type, which would then become the inferred element type.
最后一个表达式导致编译器错误,这是因为 int string 都不能隐式转换成对方。显型数组创建表达式必须这么使用:例如指定类型为 object[] 。另外,其中一个元素可以被转型到一个公共基类型,这个类型就会成为推导出的元素类型。
Implicitly typed array creation expressions can be combined with anonymous object initializers to create anonymously typed data structures. For example:
隐型数组创建表达式可以与匿名对象初始化器结合使用来创建匿名类型的数据结构。例如:
var contacts = new[] {
new {
    Name = "Chris Smith",
    PhoneNumbers = new[] { "206-555-0101", "425-882-8080" }
},
new {
    Name = "Bob Harris",
    PhoneNumbers = new[] { "650-555-0199" }
}
};
26.7 Query expressions查询表达式
Query expressions provide a language integrated syntax for queries that is similar to relational and hierarchical query languages such as SQL and XQuery.
查询表达式为查询提供了一个类似于关系和分层的查询语言 ( SQL XQuery) 语言集成 ( 译者 : intergrated 或译“整合” ) 语法。
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-clauseopt   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:
select    expression
group-clause:
group    expression   by   expression
into-clause:
into    identifier   query-body
A query-expression is classified as a non-assignment-expression, the definition of which occurs in §26.3.
查询表达式作为非赋值( non-assignment-expression 表达式分类,其定义出现在 §26.3
A query expression begins with a from clause and ends with either a select or group clause. The initial from clause can be followed by zero or more from or where clauses. Each from clause is a generator that introduces an iteration variable ranging over a sequence, and each where clause is a filter that excludes items from the result. The final select or group clause specfies the shape of the result in terms of the iteration variable(s). The select or group clause may be preceded by an orderby clause that specifies an ordering for the result. Finally, an into clause can be used to “splice” queries by treating the results of one query as a generator in a subsequent query.
查询表达式以 from 开始,结束于 select group 子句。开头的 from 子句可以跟随 0 个或者更多个 from where 子句。每个 from 子句都是一个产生器,它引入了一个迭代变量在序列上搜索;每个 where 子句是一个过滤器,它从结果中排除一些项。最后的 select group 子句指定了依据迭代变量得出的结果的外形 (shape) Select group 子句前面可有一个 orderby 子句,它指明返回结果的顺序。最后 into 子句可以通过把一条查询语句的结果作为产生器插进子序列查询中的方式来拼接查询。
In a query expression, a from clause with multiple generators is exactly equivalent to multiple consecutive from clauses with a single generator.
在查询表达式中,多个产生器的 from 子句正好等价于多个连续的带有单个产生器的 from 子句。
26.7.1 Query expression translation查询表达式translation
The C# 3.0 language does not specify the exact execution semantics of query expressions. Rather, C# 3.0 translates query expressions into invocations of methods that adhere to the query expression pattern. Specifically, query expressions are translated into invocations of methods named Where , Select , SelectMany , OrderBy , OrderByDescending , ThenBy , ThenByDescending , and GroupBy that are expected to have particular signatures and result types, as described in §26.7.2. These methods can be instance methods of the object being queried or extension methods that are external to the object, and they implement the actual execution of the query.
C# 3.0 语言没有指定查询表达式准确的执行语义。然而 C# 3.0 把查询表达式转换 (translate) 成遵循查询表达式模式的多个方法的调用。特别地,查询表达式被转换成名为 Where, Select, SelectMany, OrderBy, OrderByDescending, ThenBy, ThenByDescending GroupBy 的方法调用,这些方法预期拥有特别的签名和返回类型,描述于 §26.7.2 。这些方法可以是被查询对象的实例方法或者对象外部的扩展方法,它们实现了实际上的查询的执行过程。
The translation from query expressions to method invocations is a syntactic mapping that occurs before any type binding or overload resolution has been performed. The translation is guaranteed to be syntactically correct, but it is not guaranteed to produce semantically correct C# code. Following translation of query expressions, the resulting method invocations are processed as regular method invocations, and this may in turn uncover errors, for example if the methods do not exist, if arguments have wrong types, or if the methods are generic and type inference fails.
从查询表达式到方法调用的转换 (translation) ,是发生在任何类型绑定或重载决议执行之前的语法映射。转换要求保证语法上的正确,但不保证产生语义正确的 C# 代码。查询表达式的转换之后,产生的方法调用作为常规函数调用被处理,并且这可能依次暴露出错误。比如如果方法不存在,再比如参数类型错误或者方法是泛型的而类型推导失败。
The translation of query expressions is demonstrated through a series of examples in the following. A formal description of the translation rules is provided in a later section.
查询表达式的转换通过一系列例子示范如下。正式的转换规则的描述在后面部分。
A where clause in a query expression:
查询表达式中的 where 子句:
from c in customers
where c.City == "London
"
select c
translates to an invocation of a Where method with a synthesized lambda expression created by combining the iteration variable identifier and the expression of the where clause:
转换成带有通过结合迭代变量标识符和 where 子句表达式合成的 lambda 表达式 Where 方法。
customers.
Where(c => c.City == "London")
The example in the previous section demonstrates how a select clause that selects the innermost iteration variable is erased by the translation to method invocations.
前面部分的例子示范了选择最内层迭代变量的 select 子句是如何通过转换成方法调用而被移除的。
A select clause that selects something other than the innermost iteration variable:
Select 子句选择最内层迭代变量以外的东西:
from c in customers
where c.City == "London
"
select c.Name
translates to an invocation of a Select method with a synthesized lambda expression:
转换成合成的 lambda 表达式的 Select 方法的调用:
customers.
Where(c => c.City == "London
").
Select(c => c.Name)
A group clause:
group 子句:
from c in customers
group c.Name by c.Country
translates to an invocation of a GroupBy method:
转换成 GroupBy 方法的调用
customers.
GroupBy(c => c.Country, c => c.Name)
26.7.1.4 orderby clauses orderby子句
An orderby clause:
orderby 子句:
from c in customers
orderby c.Name
select new { c.Name, c.Phone }
translates to an invocation of an OrderBy method, or an OrderByDescending method if a descending direction was specified:
转换成 OrderBy 方法的调用,或者如果递减方向被指定时,转换成 OrderByDescending 方法的调用。
customers.
OrderBy(c => c.Name).
Select(c => new { c.Name, c.Phone })
Secondary orderings in an orderby clause:
orderby 子句中的第二个 (secondary) 次序
from c in customers
orderby c.Country, c.Balance descending
select new { c.Name, c.Country, c.Balance }
translate to invocations of ThenBy and ThenByDescending methods:
转换成对 ThenBy ThenByDescending 方法的调用:
customers.
OrderBy(c => c.Country).
ThenByDescending(c => c.Balance).
Select(c => new { c.Name, c.Country, c.Balance })
Multiple generators:
多重产生器:
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 }
translate to invocations of SelectMany for all but the innermost generator:
除了最内层产生器之外,所有的都转换成对 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 })
)
When multiple generators are combined with an orderby clause:
当多重产生器与 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 }
an additional Select is injected to collect the ordering expressions and the final result in a sequence of tuples. This is necessary such that OrderBy can operate on the entire sequence. Following OrderBy , the final result is extracted from the tuples:
额外的 Select 被注入进来搜集排序表达式 (ordering expressions) 和元组序列中的最终结果。   有必要这样做,以至 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)
An into clause:
info 子句:
from c in customers
group c by c.Country into g
select new { Country = g.Key, CustCount = g.Group.Count() }
is simply a more convenient notation for a nested query:
它是内嵌查询的一个简单而更方便的表示法:
from g in
from c in customers
group c by c.Country
select new { Country = g.Key, CustCount = g.Group.Count() }
the translation of which is:
转换如下:
customers.
GroupBy(c => c.Country).
Select(g => new { Country = g.Key, CustCount = g.Group.Count() })
26.7.2 The query expression pattern 查询表达式模式
The Query Expression Pattern establishes a pattern of methods that types can implement to support query expressions. Because query expressions are translated to method invocations by means of a syntactic mapping, types have considerable flexibility in how they implement the query expression pattern. For example, the methods of the pattern can be implemented as instance methods or as extension methods because the two have the same invocation syntax, and the methods can request delegates or expression trees because lambda expressions are convertible to both.
查询表达式模式建立了一个方法的模式,类型可以实现它来支持查询表达式。因为查询表达式利用语法映射转变成方法调用,类型在如何实现查询表达式模式时有很大的灵活性。例如:模式的方法可以被实现成实例方法或扩展方法,因为这两者具有同样的调用语法;并且方法可以要求( request delegates 或表达式树,因为 lambda 可以转换成这两者。
The recommended shape of a generic type C<T> that supports the query expression pattern is shown below. A generic type is used in order to illustrate the proper relationships between parameter and result types, but it is possible to implement the pattern for non-generic types as well.
推荐使用的支持查询表达式模式的泛型类型 C<T> 的外形 (shape) 显示如下。泛型类型被使用来例示参数和返回类型的适当关系,但是非泛型类型实现这个模式同样是可能的。
 
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; }
}
The methods above use a generic delegate type Func<A, R> , but they could equally well have used other delegate or expression tree types with the same relationships in parameter and result types.
上面的方法使用泛型 delegate 类型 Func<A, R> ,但是同样可以以参数和返回类型中的相同关系来使用其它 delegate 或表达式树类型。
Notice the recommended relationship between C<T> and O<T> which ensures that the ThenBy and ThenByDescending methods are available only on the result of an OrderBy or OrderByDescending . Also notice the recommended shape of the result of GroupBy , which is a sequence of groupings that each have a Key and Group property.
注意,推荐的 C<T> O<T> 之间的关系保证仅在 OrderBy OrderByDescending 的返回结果 ThenBy ThenByDescending 方法是可用的。也请注意,推荐的 GroupBy 结果的外形是分组的序列,每个分组具有 Key Group 属性 (property)
The Standard Query Operators (described in a separate specification) provide an implementation of the query operator pattern for any type that implements the System.Collections.Generic.IEnumerable<T> interface.
标准的查询操作符 (描述于单独的规范中)提供任意实现了 System.Collections.Generic.IEnumerable<T> 接口的 查询操作符模式的实现。
26.7.3 Formal translation rules正式的转换规则
A query expression is processed by repeatedly applying the following translations in order. Each translation is applied until there are no more occurrences of the specified pattern.
查询表达式通过依次重复应用下述转换进行处理。每个转换被应用,直到不出现指定的模式为止。
Note that in the translations that produce invocations of OrderBy and ThenBy , if the corresponding ordering clause specifies a descending direction indicator, an invocation of OrderByDescending or ThenByDescending is produced instead.
注意,在产生 OrderBy ThenBy 调用的转换中,如果对应的排序子句指定了一个递减方向的指示器, OrderByDescending ThenByDescending 就会产生。
·         A query that contains an into clause
·         包含 into 子句的查询
q1 into x q2
is translated into
转换成
from x in ( q1 ) q2
·         A from clause with multiple generators
·         带有多个产生器的 from 子句
from g1 , g2 , gn
is translated into
转换成
from g1 from g2 from gn
·         A from clause immediately followed by a where clause
·         立即跟随 where 子句的 form 子句
from x in e where f
is translated into
被转换成
from x in ( e ) . Where ( x => f )
·         A query expression with multiple from clauses, an orderby clause, and a select clause
·         多个 from ,一个 orderby 和一个 select 子句的查询表达式
from x1 in e1 from x2 in e2 orderby k1 , k2 select v
is translated into
被转换成
( 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 )
·         A query expression with multiple from clauses, an orderby clause, and a group clause
·         多个 from ,一个 orderby 和一个 group 子句的查询表达式
from x1 in e1 from x2 in e2 orderby k1 , k2 group v by g
is translated into
被转换成
( 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 )
·         A query expression with multiple from clauses and a select clause
·         多个 from 和一个 select 子句的查询表达式
from x in e from x1 in e1 select v
is translated into
被转换成
( e ) . SelectMany ( x => from x1 in e1 select v )
·         A query expression with multiple from clauses and a group clause
·         多个 from 子句和一个 group 子句的查询表达式
from x in e from x1 in e1 group v by g
is translated into
被转换成
( e ) . SelectMany ( x => from x1 in e1 group v by g )
·         A query expression with a single from clause, no orderby clause, and a select clause
·         一个 from, 没有 orderby ,一个 select 子句的查询表达式
from x in e select v
is translated into
被转换成
( e ) . Select ( x => v )
except when v is the identifier x, the translation is simply
除非当 v 是标识符 x 时,转换都是简单的
 
( e )
·         A query expression with a single from clause, no orderby clause, and a group clause
·         一个 from ,没有 orderby ,一个 group 子句的查询表达式
from x in e group v by g
is translated into
被翻译成
( e ) . GroupBy ( x => g , x => v )
except when v is the identifier x, the translation is
除了当 v 是标识符 x ,转换是
( e ) . GroupBy ( x => g )
·         A query expression with a single from clause, an orderby clause, and a select clause
·         一个 from ,一个 orderby ,一个 select 子句的查询表达式
from x in e orderby k1 , k2 select v
is translated into
被转换成
( e ) . OrderBy ( x => k1 ) . ThenBy ( x => k2 ) . Select ( x => v )
except when v is the identifier x, the translation is simply
除非当 v 是标识符 x 时,翻译是简单的。
( e ) . OrderBy ( x => k1 ) . ThenBy ( x => k2 )
·         A query expression with a single from clause, an orderby clause, and a group clause
·         一个 from ,一个 orderby ,一个 group 子句的查询表达式
from x in e orderby k1 , k2 group v by g
is translated into
被转换成
( e ) . OrderBy ( x => k1 ) . ThenBy ( x => k2 )
. GroupBy ( x => g , x => v )
except when v is the identifier x, the translation is
除非 v 是标识符 x 时,转换是
( e ) . OrderBy ( x => k1 ) . ThenBy ( x => k2 ) . GroupBy ( x => g )
26.8 Expression trees表达式树
Expression trees permit lambda expressions to be represented as data structures instead of executable code. A lambda expression that is convertible to a delegate type D is also convertible to an expression tree of type System.Query.Expression<D> . Whereas the conversion of a lambda expression to a delegate type causes executable code to be generated and referenced by a delegate, conversion to an expression tree type causes code that creates an expression tree instance to be emitted. Expression trees are efficient in-memory data representations of lambda expressions and make the structure of the expression transparent and explicit.
表达式树允许 lambda 表达式表示为数据结构而不是可执行代码。可转型到 delegate 类型 D lambda 表达式也可以转型到类型 System.Query.Expression<D> 。然而,到 delegate 类型的 lambda 表达式的转型 导致 建立表达式树实例的代码产生 (emit) 。表达式树是 lambda 表达式的高效内存数据表示,并生成表达式转换的结构,且使其显式化。
The following example represents a lambda expression both as executable code and as an expression tree. Because a conversion exists to Func<int,int> , a conversion also exists to Expression<Func<int,int>> .
前面的例子表示一个 lambda 表达式即作为可执行代码,又作为表达式树。因为存在到 Func<int,int> 的转型,也存在到 Expression<Func<int,int>> 的转型。
Func<int,int> f = x => x + 1;                   // Code
Expression<Func<int,int>> e = x => x + 1;   // Data
Following these assignments, the delegate f references a method that returns x + 1 , and the expression tree e references a data structure that describes the expression x + 1 .
紧随这些参数之后, delegate f 引用返回 x+1 的方法,表达式树 e 引用描述表达式 x+1 的数据结构。
Note
The structure of expression trees will be convered in a separate specification. This specification is not available for the PDC 2005 Technology Preview.
注意:
表达式树的结构将在单独的规范中。这个规范在PDC 2005技术预览会议上还不存在。
目录
相关文章
|
C# C++ Windows
windows程序开发中c++和c#的对照
有的选项可能仅提供C++和Windows Platform SDK中的方法(API):(1)将窗口设为顶层窗口:       c++:         //[注意]:BringWindowToTop( hwnd )不会使窗口成为TopMost窗口!         SetWindowPos(h...
882 0
|
1月前
|
C#
24. C# 编程:用户设定敌人初始血值的实现
24. C# 编程:用户设定敌人初始血值的实现
18 0
|
2月前
|
SQL 数据库连接 应用服务中间件
C#WinForm基础编程(三)
C#WinForm基础编程
71 0
|
2月前
C#WinForm基础编程(二)
C#WinForm基础编程
55 0
|
2月前
|
C# 数据安全/隐私保护
C#WinForm基础编程(一)
C#WinForm基础编程
59 0
|
4月前
|
数据采集 前端开发 C#
C#编程艺术:Fizzler库助您高效爬取www.twitter.com音频
Twitter是全球最大的社交媒体平台之一,包含丰富的音频资源。用户可以在Twitter上发布、转发、评论和收听各种音频内容,如音乐、播客、新闻、故事等,直接从Twitter抓取音频数据并非易事,尤其是在考虑到可能的封锁和反爬虫机制。Twitter会对频繁访问的IP地址进行限制或封禁,以防止恶意爬虫的行为。因此,我们需要使用一些技术手段来规避这些障碍,确保稳定而高效的数据访问。
C#编程艺术:Fizzler库助您高效爬取www.twitter.com音频
|
3月前
|
程序员 C#
深入理解 C# 编程:枚举、文件处理、异常处理和数字相加
枚举是一个特殊的“类”,表示一组常量(不可更改/只读变量)。 要创建枚举,请使用 enum 关键字(而不是 class 或 interface),并用逗号分隔枚举项:
37 0
|
3月前
|
定位技术 C# 图形学
Unity和C#游戏编程入门:创建迷宫小球游戏示例
Unity和C#游戏编程入门:创建迷宫小球游戏示例
71 2
|
4月前
|
C# C++
C# 高效率编程 “多线程” 的基本使用
C# 高效率编程 “多线程” 的基本使用