语句Statements

C # 提供了多种语句。C# provides a variety of statements. 对于在 C 和 c + + 中进行编程的开发人员,这些语句中的大部分将很熟悉。Most of these statements will be familiar to developers who have programmed in C and C++.

statement
    : labeled_statement
    | declaration_statement
    | embedded_statement
    ;

embedded_statement
    : block
    | empty_statement
    | expression_statement
    | selection_statement
    | iteration_statement
    | jump_statement
    | try_statement
    | checked_statement
    | unchecked_statement
    | lock_statement
    | using_statement
    | yield_statement
    | embedded_statement_unsafe
    ;

Embedded_statement 非终止符用于在其他语句中显示的语句。The embedded_statement nonterminal is used for statements that appear within other statements. 使用 embedded_statement 而不是 语句 不包括在这些上下文中声明语句和标记语句的使用。The use of embedded_statement rather than statement excludes the use of declaration statements and labeled statements in these contexts. 示例The example

void F(bool b) {
    if (b)
        int i = 44;
}

导致编译时错误,因为 if 语句需要 embedded_statement 而不是 语句 用于 if 分支。results in a compile-time error because an if statement requires an embedded_statement rather than a statement for its if branch. 如果允许此代码,则将声明该变量 i ,但绝不能使用它。If this code were permitted, then the variable i would be declared, but it could never be used. 但请注意,通过 i 将的声明放置在块中,该示例是有效的。Note, however, that by placing i's declaration in a block, the example is valid.

终结点和可访问性End points and reachability

每个语句都有一个 终结点Every statement has an end point. 简而言之,语句的结束点是紧跟在语句之后的位置。In intuitive terms, the end point of a statement is the location that immediately follows the statement. 复合语句的执行规则 (包含嵌入语句的语句) 指定控制到达嵌入语句的终结点时所采取的操作。The execution rules for composite statements (statements that contain embedded statements) specify the action that is taken when control reaches the end point of an embedded statement. 例如,当控件到达块中语句的终点时,控制将转移到块中的下一条语句。For example, when control reaches the end point of a statement in a block, control is transferred to the next statement in the block.

如果语句可能是通过执行来访问的,则该语句称为 * 可 访问If a statement can possibly be reached by execution, the statement is said to be *reachable _. 相反,如果不可能执行语句,则该语句称为 _ * 无法 访问Conversely, if there is no possibility that a statement will be executed, the statement is said to be _*unreachable**.

示例中In the example

void F() {
    Console.WriteLine("reachable");
    goto Label;
    Console.WriteLine("unreachable");
    Label:
    Console.WriteLine("reachable");
}

无法访问的第二个调用, Console.WriteLine 因为不可能执行该语句。the second invocation of Console.WriteLine is unreachable because there is no possibility that the statement will be executed.

如果编译器确定无法访问某个语句,则会报告警告。A warning is reported if the compiler determines that a statement is unreachable. 它特别不是错误,无法访问语句。It is specifically not an error for a statement to be unreachable.

若要确定特定的语句或终结点是否可访问,编译器将根据为每个语句定义的可访问性规则执行流分析。To determine whether a particular statement or end point is reachable, the compiler performs flow analysis according to the reachability rules defined for each statement. 流分析考虑控制语句行为的 常量表达式) (常量 表达式的值,但不考虑非常量表达式的可能值。The flow analysis takes into account the values of constant expressions (Constant expressions) that control the behavior of statements, but the possible values of non-constant expressions are not considered. 换句话说,出于控制流分析的目的,给定类型的非常量表达式被视为具有该类型的任何可能值。In other words, for purposes of control flow analysis, a non-constant expression of a given type is considered to have any possible value of that type.

示例中In the example

void F() {
    const int i = 1;
    if (i == 2) Console.WriteLine("unreachable");
}

语句的布尔表达式 if 是常量表达式,因为运算符的两个操作数 == 都是常量。the boolean expression of the if statement is a constant expression because both operands of the == operator are constants. 在编译时计算常量表达式,生成值时 falseConsole.WriteLine 会将调用视为不可访问。As the constant expression is evaluated at compile-time, producing the value false, the Console.WriteLine invocation is considered unreachable. 但是,如果 i 将更改为本地变量However, if i is changed to be a local variable

void F() {
    int i = 1;
    if (i == 2) Console.WriteLine("reachable");
}

Console.WriteLine调用被视为可访问,即使实际上它将永远不会执行。the Console.WriteLine invocation is considered reachable, even though, in reality, it will never be executed.

函数成员的 始终被认为是可访问的。The block of a function member is always considered reachable. 通过依次计算块中每个语句的可访问性规则,可以确定任何给定语句的可访问性。By successively evaluating the reachability rules of each statement in a block, the reachability of any given statement can be determined.

示例中In the example

void F(int x) {
    Console.WriteLine("start");
    if (x < 0) Console.WriteLine("negative");
}

第二个的可访问性 Console.WriteLine 确定如下:the reachability of the second Console.WriteLine is determined as follows:

  • 第一个 Console.WriteLine 表达式语句是可访问的,因为该 F 方法的块是可访问的。The first Console.WriteLine expression statement is reachable because the block of the F method is reachable.
  • 第一个表达式语句的结束点是可访问的 Console.WriteLine ,因为该语句是可访问的。The end point of the first Console.WriteLine expression statement is reachable because that statement is reachable.
  • if由于第一个 expression 语句的结束点 Console.WriteLine 是可访问的,因此该语句是可访问的。The if statement is reachable because the end point of the first Console.WriteLine expression statement is reachable.
  • 可访问第二个 Console.WriteLine expression 语句,因为该语句的布尔表达式没有 if 常数值 falseThe second Console.WriteLine expression statement is reachable because the boolean expression of the if statement does not have the constant value false.

在以下两种情况下,可能会发生编译时错误,导致语句的终结点可到达:There are two situations in which it is a compile-time error for the end point of a statement to be reachable:

  • 由于 switch 语句不允许 switch 节 "贯穿" 到下一个开关部分,因此在开关部分的语句列表的终结点可以访问时,会发生编译时错误。Because the switch statement does not permit a switch section to "fall through" to the next switch section, it is a compile-time error for the end point of the statement list of a switch section to be reachable. 如果发生此错误,则通常指示 break 缺少语句。If this error occurs, it is typically an indication that a break statement is missing.
  • 对于计算要访问的值的函数成员块,它是一个编译时错误。It is a compile-time error for the end point of the block of a function member that computes a value to be reachable. 如果发生此错误,则通常指示 return 缺少语句。If this error occurs, it typically is an indication that a return statement is missing.

Blocks

使用 代码块,可以在允许编写一个语句的上下文中编写多个语句。A block permits multiple statements to be written in contexts where a single statement is allowed.

block
    : '{' statement_list? '}'
    ;

由可选的 statement_list (语句列出) ,括在大括号中。A block consists of an optional statement_list (Statement lists), enclosed in braces. 如果省略了语句列表,则称块为空。If the statement list is omitted, the block is said to be empty.

块可以包含声明语句 (声明语句) 。A block may contain declaration statements (Declaration statements). 块中声明的局部变量或常量的范围为块。The scope of a local variable or constant declared in a block is the block.

块的执行方式如下:A block is executed as follows:

  • 如果块为空,控制将被传输到块的终结点。If the block is empty, control is transferred to the end point of the block.
  • 如果块不为空,则将控制转移到语句列表。If the block is not empty, control is transferred to the statement list. 当和如果控件到达语句列表的终点时,控制将被传输到块的终结点。When and if control reaches the end point of the statement list, control is transferred to the end point of the block.

如果块本身是可访问的,则块的语句列表是可访问的。The statement list of a block is reachable if the block itself is reachable.

如果块为空或语句列表的终结点是可访问的,则块的终结点是可访问的。The end point of a block is reachable if the block is empty or if the end point of the statement list is reachable.

包含一个或多个 yield 语句 (yield 语句) 称为迭代器块的块。A block that contains one or more yield statements (The yield statement) is called an iterator block. 迭代器块用于 实现) 迭代器 (迭代器 中的函数成员。Iterator blocks are used to implement function members as iterators (Iterators). 迭代器块适用于一些附加限制:Some additional restrictions apply to iterator blocks:

  • return语句会出现在迭代器块 (的编译时错误,但 yield return 允许语句) 。It is a compile-time error for a return statement to appear in an iterator block (but yield return statements are permitted).
  • 迭代器块包含不安全 上下文 (不安全上下文) 的编译时错误。It is a compile-time error for an iterator block to contain an unsafe context (Unsafe contexts). 迭代器块始终定义安全上下文,即使其声明嵌套在不安全的上下文中也是如此。An iterator block always defines a safe context, even when its declaration is nested in an unsafe context.

语句列表Statement lists

*语句列表 _ 由一个或多个按顺序写入的语句组成。A *statement list _ consists of one or more statements written in sequence. 语句列表出现在 _block * s () 和 switch_block (switch 语句) 中。Statement lists occur in _block*s (Blocks) and in switch_block s (The switch statement).

statement_list
    : statement+
    ;

语句列表通过将控制转移到第一条语句来执行。A statement list is executed by transferring control to the first statement. 当和如果控件到达语句的结束点时,控制将转移到下一个语句。When and if control reaches the end point of a statement, control is transferred to the next statement. 当和如果控件到达最后一个语句的终点时,控件将被传输到语句列表的终结点。When and if control reaches the end point of the last statement, control is transferred to the end point of the statement list.

如果以下至少一个条件为 true,则语句列表中的语句是可访问的:A statement in a statement list is reachable if at least one of the following is true:

  • 语句是第一条语句,语句列表本身是可访问的。The statement is the first statement and the statement list itself is reachable.
  • 可以访问前面语句的终点。The end point of the preceding statement is reachable.
  • 语句是标记的语句,并且标签由可访问的语句引用 gotoThe statement is a labeled statement and the label is referenced by a reachable goto statement.

如果列表中最后一个语句的结束点是可访问的,则该语句列表的终结点是可访问的。The end point of a statement list is reachable if the end point of the last statement in the list is reachable.

空语句The empty statement

Empty_statement 不执行任何操作。An empty_statement does nothing.

empty_statement
    : ';'
    ;

在需要语句的上下文中没有要执行的操作时,将使用空语句。An empty statement is used when there are no operations to perform in a context where a statement is required.

空语句的执行只是将控制转移到语句的终结点。Execution of an empty statement simply transfers control to the end point of the statement. 因此,如果可以访问空语句,则可以访问空语句的结束点。Thus, the end point of an empty statement is reachable if the empty statement is reachable.

使用空的正文编写语句时,可以使用空语句 whileAn empty statement can be used when writing a while statement with a null body:

bool ProcessMessage() {...}

void ProcessMessages() {
    while (ProcessMessage())
        ;
}

此外,空语句还可用于在块的结束 "" 之前声明标签 }Also, an empty statement can be used to declare a label just before the closing "}" of a block:

void F() {
    ...
    if (done) goto exit;
    ...
    exit: ;
}

带标签的语句Labeled statements

Labeled_statement 允许语句以标签为前缀。A labeled_statement permits a statement to be prefixed by a label. 标记语句允许出现在块中,但不允许作为嵌入语句使用。Labeled statements are permitted in blocks, but are not permitted as embedded statements.

labeled_statement
    : identifier ':' statement
    ;

标记语句使用 标识符 给定的名称声明标签。A labeled statement declares a label with the name given by the identifier. 标签的作用域是在其中声明标签的整个块,包括任何嵌套块。The scope of a label is the whole block in which the label is declared, including any nested blocks. 对于具有相同名称的两个同名标签,它是编译时错误。It is a compile-time error for two labels with the same name to have overlapping scopes.

可以在 goto 标签范围内 (goto 语句) 的语句中引用标签。A label can be referenced from goto statements (The goto statement) within the scope of the label. 这意味着 goto 语句可以将控制转移到块中,而不是块中的块。This means that goto statements can transfer control within blocks and out of blocks, but never into blocks.

标签具有自己的声明空间,不会干扰其他标识符。Labels have their own declaration space and do not interfere with other identifiers. 示例The example

int F(int x) {
    if (x >= 0) goto x;
    x = -x;
    x: return x;
}

有效并且使用名称 x 作为参数和标签。is valid and uses the name x as both a parameter and a label.

标记语句的执行与标签后面的语句的执行完全对应。Execution of a labeled statement corresponds exactly to execution of the statement following the label.

除了正常的控制流提供的可访问性外,如果标签由可访问的语句引用,则可以访问标记的语句 gotoIn addition to the reachability provided by normal flow of control, a labeled statement is reachable if the label is referenced by a reachable goto statement. (异常:如果 goto 语句位于 try 包含块的内 finally ,并且标记的语句在之外 try ,并且 finally 无法访问块的终结点,则无法从该语句访问标记的语句 goto 。 ) (Exception: If a goto statement is inside a try that includes a finally block, and the labeled statement is outside the try, and the end point of the finally block is unreachable, then the labeled statement is not reachable from that goto statement.)

声明语句Declaration statements

声明局部变量或常量的 declaration_statementA declaration_statement declares a local variable or constant. 声明语句在块中是允许的,但不允许作为嵌入语句。Declaration statements are permitted in blocks, but are not permitted as embedded statements.

declaration_statement
    : local_variable_declaration ';'
    | local_constant_declaration ';'
    ;

局部变量声明Local variable declarations

Local_variable_declaration 声明一个或多个局部变量。A local_variable_declaration declares one or more local variables.

local_variable_declaration
    : local_variable_type local_variable_declarators
    ;

local_variable_type
    : type
    | 'var'
    ;

local_variable_declarators
    : local_variable_declarator
    | local_variable_declarators ',' local_variable_declarator
    ;

local_variable_declarator
    : identifier
    | identifier '=' local_variable_initializer
    ;

local_variable_initializer
    : expression
    | array_initializer
    | local_variable_initializer_unsafe
    ;

Local_variable_declarationlocal_variable_type 直接指定声明引入的变量类型,或者使用标识符指示 var 应基于初始值设定项推断类型。The local_variable_type of a local_variable_declaration either directly specifies the type of the variables introduced by the declaration, or indicates with the identifier var that the type should be inferred based on an initializer. 该类型后跟一个 local_variable_declarator s 列表,其中每个都引入一个新变量。The type is followed by a list of local_variable_declarator s, each of which introduces a new variable. Local_variable_declarator 包含命名变量的 标识符,可选择后跟一个 " = " 标记和一个提供变量初始值的 local_variable_initializerA local_variable_declarator consists of an identifier that names the variable, optionally followed by an "=" token and a local_variable_initializer that gives the initial value of the variable.

在局部变量声明的上下文中,标识符 var 用作上下文关键字 (关键字) 。如果将 local_variable_type 指定为 var ,并且没有任何名为的类型 var 在范围内,则声明是一个 隐式类型的局部变量声明,其类型从关联的初始值设定项表达式的类型推断而来。In the context of a local variable declaration, the identifier var acts as a contextual keyword (Keywords).When the local_variable_type is specified as var and no type named var is in scope, the declaration is an implicitly typed local variable declaration, whose type is inferred from the type of the associated initializer expression. 隐式类型的局部变量声明受到以下限制:Implicitly typed local variable declarations are subject to the following restrictions:

  • Local_variable_declaration 不能包含多个 local_variable_declaratorThe local_variable_declaration cannot include multiple local_variable_declarator s.
  • Local_variable_declarator 必须包含 local_variable_initializerThe local_variable_declarator must include a local_variable_initializer.
  • Local_variable_initializer 必须是 表达式The local_variable_initializer must be an expression.
  • 初始值设定项 表达式 必须具有编译时类型。The initializer expression must have a compile-time type.
  • 初始值设定项 表达式 不能引用声明的变量本身The initializer expression cannot refer to the declared variable itself

下面是错误的隐式类型化局部变量声明的示例: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, array initializer not permitted
var z = null;        // Error, null does not have a type
var u = x => x + 1;  // Error, anonymous functions do not have a type
var v = v++;         // Error, initializer cannot refer to variable itself

局部变量的值是在表达式中使用 simple_name (简单名称) 获取的,而局部变量的值是使用 赋值 (赋值运算符) 进行修改的。The value of a local variable is obtained in an expression using a simple_name (Simple names), and the value of a local variable is modified using an assignment (Assignment operators). 局部变量必须在获取其值的每个位置 (明确赋值) 。A local variable must be definitely assigned (Definite assignment) at each location where its value is obtained.

local_variable_declaration 中声明的局部变量的作用域是在其中进行声明的块。The scope of a local variable declared in a local_variable_declaration is the block in which the declaration occurs. 在本地变量 local_variable_declarator 之前的文本位置引用局部变量是错误的。It is an error to refer to a local variable in a textual position that precedes the local_variable_declarator of the local variable. 在局部变量的作用域内,使用相同的名称声明另一个局部变量或常量时,会发生编译时错误。Within the scope of a local variable, it is a compile-time error to declare another local variable or constant with the same name.

声明多个变量的局部变量声明等效于多个具有相同类型的单个变量的声明。A local variable declaration that declares multiple variables is equivalent to multiple declarations of single variables with the same type. 此外,局部变量声明中的变量初始值设定项完全对应于紧接在声明后插入的赋值语句。Furthermore, a variable initializer in a local variable declaration corresponds exactly to an assignment statement that is inserted immediately after the declaration.

示例The example

void F() {
    int x = 1, y, z = x * 2;
}

完全对应于corresponds exactly to

void F() {
    int x; x = 1;
    int y;
    int z; z = x * 2;
}

在隐式类型的局部变量声明中,声明的局部变量的类型将被视为与用于初始化变量的表达式的类型相同。In an implicitly typed local variable declaration, the type of the local variable being declared is taken to be the same as the type of the expression used to initialize the variable. 例如:For example:

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:

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>();

局部常量声明Local constant declarations

一个 local_constant_declaration 声明一个或多个本地常量。A local_constant_declaration declares one or more local constants.

local_constant_declaration
    : 'const' type constant_declarators
    ;

constant_declarators
    : constant_declarator (',' constant_declarator)*
    ;

constant_declarator
    : identifier '=' constant_expression
    ;

Local_constant_declaration类型 指定声明引入的常量的类型。The type of a local_constant_declaration specifies the type of the constants introduced by the declaration. 该类型后跟一个 constant_declarator s 列表,其中每个都引入一个新常量。The type is followed by a list of constant_declarator s, each of which introduces a new constant. Constant_declarator 包含一个标识符,该 标识符 对常量进行命名,后跟一个 " = " 标记,后跟一个 constant_expression (常数表达式) ,该表达式提供常量的值。A constant_declarator consists of an identifier that names the constant, followed by an "=" token, followed by a constant_expression (Constant expressions) that gives the value of the constant.

局部常量声明的类型和 constant_expression 必须与常量成员声明的 类型 和 (常量) 相同。The type and constant_expression of a local constant declaration must follow the same rules as those of a constant member declaration (Constants).

使用 simple_name (简单名称) ,可在表达式中获取本地常量的值。The value of a local constant is obtained in an expression using a simple_name (Simple names).

局部常数的作用域是在其中进行声明的块。The scope of a local constant is the block in which the declaration occurs. constant_declarator 之前的文本位置引用本地常量是错误的。It is an error to refer to a local constant in a textual position that precedes its constant_declarator. 在局部常数的范围内,使用相同的名称声明另一个局部变量或常量时,会发生编译时错误。Within the scope of a local constant, it is a compile-time error to declare another local variable or constant with the same name.

声明多个常量的局部常量声明等效于多个具有相同类型的单个常量的声明。A local constant declaration that declares multiple constants is equivalent to multiple declarations of single constants with the same type.

表达式语句Expression statements

Expression_statement 计算给定表达式的值。An expression_statement evaluates a given expression. 由表达式计算的值(如果有)将被丢弃。The value computed by the expression, if any, is discarded.

expression_statement
    : statement_expression ';'
    ;

statement_expression
    : invocation_expression
    | null_conditional_invocation_expression
    | object_creation_expression
    | assignment
    | post_increment_expression
    | post_decrement_expression
    | pre_increment_expression
    | pre_decrement_expression
    | await_expression
    ;

并非所有表达式都允许作为语句。Not all expressions are permitted as statements. 具体而言,诸如 x + y 和的表达式( x == 1 仅计算将被放弃) (值)不允许作为语句。In particular, expressions such as x + y and x == 1 that merely compute a value (which will be discarded), are not permitted as statements.

执行 expression_statement 将计算包含的表达式,然后将控制转移到 expression_statement 的终结点。Execution of an expression_statement evaluates the contained expression and then transfers control to the end point of the expression_statement. 如果 expression_statement 可访问,则可到达 expression_statement 的终结点。The end point of an expression_statement is reachable if that expression_statement is reachable.

选择语句Selection statements

选择语句根据某个表达式的值为执行选择多个可能的语句之一。Selection statements select one of a number of possible statements for execution based on the value of some expression.

selection_statement
    : if_statement
    | switch_statement
    ;

if 语句The if statement

if语句基于布尔表达式的值来选择要执行的语句。The if statement selects a statement for execution based on the value of a boolean expression.

if_statement
    : 'if' '(' boolean_expression ')' embedded_statement
    | 'if' '(' boolean_expression ')' embedded_statement 'else' embedded_statement
    ;

else部件与语法允许的上一个词法上最近的语句相关联 ifAn else part is associated with the lexically nearest preceding if that is allowed by the syntax. 因此, if 形式的语句Thus, an if statement of the form

if (x) if (y) F(); else G();

等效于is equivalent to

if (x) {
    if (y) {
        F();
    }
    else {
        G();
    }
}

if语句的执行方式如下:An if statement is executed as follows:

  • 计算) boolean_expression (布尔表达式The boolean_expression (Boolean expressions) is evaluated.
  • 如果布尔表达式产生了 true ,则将控制转移到第一个嵌入语句。If the boolean expression yields true, control is transferred to the first embedded statement. 当和如果控件到达该语句的终点时,控制将被传输到语句的终结点 ifWhen and if control reaches the end point of that statement, control is transferred to the end point of the if statement.
  • 如果布尔表达式的结果 false 为,并且 else 存在某个部分,则将控制转移到第二个嵌入语句。If the boolean expression yields false and if an else part is present, control is transferred to the second embedded statement. 当和如果控件到达该语句的终点时,控制将被传输到语句的终结点 ifWhen and if control reaches the end point of that statement, control is transferred to the end point of the if statement.
  • 如果布尔表达式产生 false 并且如果某个 else 部分不存在,则将控制转移到该语句的结束点 ifIf the boolean expression yields false and if an else part is not present, control is transferred to the end point of the if statement.

if如果 if 语句是可访问的并且布尔表达式不具有常数值,则可以访问语句的第一个嵌入语句 falseThe first embedded statement of an if statement is reachable if the if statement is reachable and the boolean expression does not have the constant value false.

if如果 if 语句是可访问的并且布尔表达式不具有常数值,则语句的第二个嵌入语句(如果有)是可访问的 trueThe second embedded statement of an if statement, if present, is reachable if the if statement is reachable and the boolean expression does not have the constant value true.

if如果至少有一个嵌入语句的结束点可访问,则该语句的结束点是可访问的。The end point of an if statement is reachable if the end point of at least one of its embedded statements is reachable. 此外, if else 如果 if 语句是可访问的并且布尔表达式不具有常数值,则可访问没有任何部分的语句的结束点 trueIn addition, the end point of an if statement with no else part is reachable if the if statement is reachable and the boolean expression does not have the constant value true.

Switch 语句The switch statement

Switch 语句为执行选择一个语句列表,其中包含与 switch 表达式的值相对应的关联 switch 标签。The switch statement selects for execution a statement list having an associated switch label that corresponds to the value of the switch expression.

switch_statement
    : 'switch' '(' expression ')' switch_block
    ;

switch_block
    : '{' switch_section* '}'
    ;

switch_section
    : switch_label+ statement_list
    ;

switch_label
    : 'case' constant_expression ':'
    | 'default' ':'
    ;

Switch_statement 包含关键字 switch ,后跟带括号的表达式 (称为 switch 表达式) ,后跟一个 switch_blockA switch_statement consists of the keyword switch, followed by a parenthesized expression (called the switch expression), followed by a switch_block. Switch_block 由零个或多个 switch_section 组成,括在大括号中。The switch_block consists of zero or more switch_section s, enclosed in braces. 每个 switch_section 都包含一个或多个 switch_label,后面跟有 statement_list (语句列出) 。Each switch_section consists of one or more switch_label s followed by a statement_list (Statement lists).

语句的 管理类型 switch 由 switch 表达式建立。The governing type of a switch statement is established by the switch expression.

  • 如果开关表达式的类型为、、、、、、、、、、 sbyte byte short ushort int uint long ulong bool char stringenum_type,或者,如果它是对应于这些类型之一的可为 null 的类型,则为该语句的管理类型 switchIf the type of the switch expression is sbyte, byte, short, ushort, int, uint, long, ulong, bool, char, string, or an enum_type, or if it is the nullable type corresponding to one of these types, then that is the governing type of the switch statement.
  • 否则,必须有一个用户定义的隐式转换 (用户定义的转换 ,) 必须从 switch 表达式的类型存在,转换为以下某个可能的管理类型:、、、、、、、、、 sbyte byte short ushort int uint long ulong char string 或,这是与这些类型之一对应的可以为 null 的类型。Otherwise, exactly one user-defined implicit conversion (User-defined conversions) must exist from the type of the switch expression to one of the following possible governing types: sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or, a nullable type corresponding to one of those types.
  • 否则,如果不存在这样的隐式转换,或者存在多个这样的隐式转换,则会发生编译时错误。Otherwise, if no such implicit conversion exists, or if more than one such implicit conversion exists, a compile-time error occurs.

每个标签的常量表达式 case 必须表示一个可隐式转换 (隐式转换) 到该语句的管理类型的值 switchThe constant expression of each case label must denote a value that is implicitly convertible (Implicit conversions) to the governing type of the switch statement. 如果同一语句中的两个或更多 case 标签 switch 指定同一常数值,则会发生编译时错误。A compile-time error occurs if two or more case labels in the same switch statement specify the same constant value.

Switch 语句中最多只能有一个 default 标签。There can be at most one default label in a switch statement.

switch语句的执行方式如下:A switch statement is executed as follows:

  • 将计算 switch 表达式并将其转换为管理类型。The switch expression is evaluated and converted to the governing type.
  • 如果在 case 同一语句中的标签中指定的一个常量 switch 等于 switch 表达式的值,则控制将转移到匹配的标签后面的语句列表中 caseIf one of the constants specified in a case label in the same switch statement is equal to the value of the switch expression, control is transferred to the statement list following the matched case label.
  • 如果在 case 同一语句的标签中指定的常量均 switch 不等于 switch 表达式的值,并且如果 default 有标签,则会将控制转移到标签后面的语句列表中 defaultIf none of the constants specified in case labels in the same switch statement is equal to the value of the switch expression, and if a default label is present, control is transferred to the statement list following the default label.
  • 如果在 case 同一语句的标签中指定的常量均 switch 不等于 switch 表达式的值,并且如果不 default 存在任何标签,则会将控制转移到语句的终点 switchIf none of the constants specified in case labels in the same switch statement is equal to the value of the switch expression, and if no default label is present, control is transferred to the end point of the switch statement.

如果开关部分的语句列表的结束点是可访问的,则会发生编译时错误。If the end point of the statement list of a switch section is reachable, a compile-time error occurs. 这称为 "不贯穿" 规则。This is known as the "no fall through" rule. 示例The example

switch (i) {
case 0:
    CaseZero();
    break;
case 1:
    CaseOne();
    break;
default:
    CaseOthers();
    break;
}

有效,因为没有开关部分具有可访问的终结点。is valid because no switch section has a reachable end point. 与 C 和 c + + 不同,switch 节的执行不允许 "贯穿" 到下一个开关部分,示例Unlike C and C++, execution of a switch section is not permitted to "fall through" to the next switch section, and the example

switch (i) {
case 0:
    CaseZero();
case 1:
    CaseZeroOrOne();
default:
    CaseAny();
}

导致编译时错误。results in a compile-time error. 当执行 switch 节后,若要执行另一个 switch 节, goto case goto default 必须使用显式或语句:When execution of a switch section is to be followed by execution of another switch section, an explicit goto case or goto default statement must be used:

switch (i) {
case 0:
    CaseZero();
    goto case 1;
case 1:
    CaseZeroOrOne();
    goto default;
default:
    CaseAny();
    break;
}

Switch_section 允许使用多个标签。Multiple labels are permitted in a switch_section. 示例The example

switch (i) {
case 0:
    CaseZero();
    break;
case 1:
    CaseOne();
    break;
case 2:
default:
    CaseTwo();
    break;
}

有效。is valid. 该示例不违反 "无贯穿" 规则,因为标签 case 2: 和属于 default: 相同 switch_sectionThe example does not violate the "no fall through" rule because the labels case 2: and default: are part of the same switch_section.

"不贯穿" 规则可防止在意外省略语句时出现在 C 和 c + + 中的常见错误类 breakThe "no fall through" rule prevents a common class of bugs that occur in C and C++ when break statements are accidentally omitted. 此外,由于此规则,可以任意重新排列语句的 switch 部分, switch 而不会影响语句的行为。In addition, because of this rule, the switch sections of a switch statement can be arbitrarily rearranged without affecting the behavior of the statement. 例如,上述语句的各个部分 switch 可以反转,而不会影响语句的行为:For example, the sections of the switch statement above can be reversed without affecting the behavior of the statement:

switch (i) {
default:
    CaseAny();
    break;
case 1:
    CaseZeroOrOne();
    goto default;
case 0:
    CaseZero();
    goto case 1;
}

Switch 部分的语句列表通常以 breakgoto casegoto default 语句结束,但允许任何不能访问语句列表的终结点的构造。The statement list of a switch section typically ends in a break, goto case, or goto default statement, but any construct that renders the end point of the statement list unreachable is permitted. 例如, while 已知由布尔表达式控制的语句 true 永远不会到达其终结点。For example, a while statement controlled by the boolean expression true is known to never reach its end point. 同样, throwreturn 语句始终将控制转移到其他位置,而永远不会到达终结点。Likewise, a throw or return statement always transfers control elsewhere and never reaches its end point. 因此,下面的示例是有效的:Thus, the following example is valid:

switch (i) {
case 0:
    while (true) F();
case 1:
    throw new ArgumentException();
case 2:
    return;
}

语句的管理类型 switch 可以是类型 stringThe governing type of a switch statement may be the type string. 例如:For example:

void DoCommand(string command) {
    switch (command.ToLower()) {
    case "run":
        DoRun();
        break;
    case "save":
        DoSave();
        break;
    case "quit":
        DoQuit();
        break;
    default:
        InvalidCommand(command);
        break;
    }
}

与字符串相等运算符一样 (字符串相等运算符) ,该 switch 语句区分大小写,并且仅当 switch 表达式字符串与标签常量完全匹配时,才会执行给定的 switch 节 caseLike the string equality operators (String equality operators), the switch statement is case sensitive and will execute a given switch section only if the switch expression string exactly matches a case label constant.

当语句的管理类型 switch 为时 string ,允许值 null 作为 case 标签常量。When the governing type of a switch statement is string, the value null is permitted as a case label constant.

Switch_blockstatement_list 可能包含声明语句 (声明语句) 。The statement_list s of a switch_block may contain declaration statements (Declaration statements). Switch 块中声明的局部变量或常量的范围为 switch 块。The scope of a local variable or constant declared in a switch block is the switch block.

如果 switch 可以访问该语句,并且至少满足以下条件之一,则可到达给定开关部分的语句列表:The statement list of a given switch section is reachable if the switch statement is reachable and at least one of the following is true:

  • Switch 表达式是一个非常量的值。The switch expression is a non-constant value.
  • Switch 表达式是一个与开关部分中的标签匹配的常量值 caseThe switch expression is a constant value that matches a case label in the switch section.
  • Switch 表达式是不与任何标签匹配的常数值 case ,并且开关部分包含 default 标签。The switch expression is a constant value that doesn't match any case label, and the switch section contains the default label.
  • 开关部分的开关标签由可访问的 goto casegoto default 语句引用。A switch label of the switch section is referenced by a reachable goto case or goto default statement.

switch如果以下至少一个条件为 true,则可以访问语句的结束点:The end point of a switch statement is reachable if at least one of the following is true:

  • switch语句包含可访问语句 break ,该语句可退出 switch 语句。The switch statement contains a reachable break statement that exits the switch statement.
  • switch 语句可访问,switch 表达式为非常量值,并且不 default 存在任何标签。The switch statement is reachable, the switch expression is a non-constant value, and no default label is present.
  • switch 语句是可访问的,switch 表达式是不与任何标签匹配的常数值 case ,并且不 default 存在任何标签。The switch statement is reachable, the switch expression is a constant value that doesn't match any case label, and no default label is present.

迭代语句Iteration statements

迭代语句重复执行嵌入语句。Iteration statements repeatedly execute an embedded statement.

iteration_statement
    : while_statement
    | do_statement
    | for_statement
    | foreach_statement
    ;

While 语句The while statement

while语句有条件地执行一个嵌入语句零次或多次。The while statement conditionally executes an embedded statement zero or more times.

while_statement
    : 'while' '(' boolean_expression ')' embedded_statement
    ;

while语句的执行方式如下:A while statement is executed as follows:

  • 计算) boolean_expression (布尔表达式The boolean_expression (Boolean expressions) is evaluated.
  • 如果布尔表达式产生了 true ,则将控制转移到嵌入语句。If the boolean expression yields true, control is transferred to the embedded statement. 当和如果控件到达嵌入语句的结束点 (可能来自语句) 的执行时 continue ,控件将转移到语句的开头 whileWhen and if control reaches the end point of the embedded statement (possibly from execution of a continue statement), control is transferred to the beginning of the while statement.
  • 如果布尔表达式产生 false ,控制将被传输到语句的结束点 whileIf the boolean expression yields false, control is transferred to the end point of the while statement.

在语句的嵌入语句中 whilebreak (break 语句) 的语句可用于将控制转移到语句的终结点 while (从而结束嵌入语句的结束迭代) ,并且 (continue continue 语句) 的语句可用于将控制转移到嵌入语句的终结点 (从而) 执行语句的另一次迭代 whileWithin the embedded statement of a while statement, a break statement (The break statement) may be used to transfer control to the end point of the while statement (thus ending iteration of the embedded statement), and a continue statement (The continue statement) may be used to transfer control to the end point of the embedded statement (thus performing another iteration of the while statement).

while如果 while 语句是可访问的并且布尔表达式不具有常数值,则可以访问语句的嵌入语句 falseThe embedded statement of a while statement is reachable if the while statement is reachable and the boolean expression does not have the constant value false.

while如果以下至少一个条件为 true,则可以访问语句的结束点:The end point of a while statement is reachable if at least one of the following is true:

  • while语句包含可访问语句 break ,该语句可退出 while 语句。The while statement contains a reachable break statement that exits the while statement.
  • while 语句可访问,且布尔表达式没有常数值 trueThe while statement is reachable and the boolean expression does not have the constant value true.

Do 语句The do statement

do语句有条件地执行一次或多次嵌入式语句。The do statement conditionally executes an embedded statement one or more times.

do_statement
    : 'do' embedded_statement 'while' '(' boolean_expression ')' ';'
    ;

do语句的执行方式如下:A do statement is executed as follows:

  • 控件将被传输到嵌入语句。Control is transferred to the embedded statement.
  • 当和如果控件到达嵌入语句的终点 (可能来自语句) 的执行时 continue ,将计算 Boolean_expression (布尔) 表达式When and if control reaches the end point of the embedded statement (possibly from execution of a continue statement), the boolean_expression (Boolean expressions) is evaluated. 如果布尔表达式产生 true ,控制将被传输到语句的开头 doIf the boolean expression yields true, control is transferred to the beginning of the do statement. 否则,控制将转移到语句的结束点 doOtherwise, control is transferred to the end point of the do statement.

在语句的嵌入语句中 dobreak (break 语句) 的语句可用于将控制转移到语句的终结点 do (从而结束嵌入语句的结束迭代) ,并且 (continue continue 语句) 的语句可用于将控制转移到嵌入语句的终结点。Within the embedded statement of a do statement, a break statement (The break statement) may be used to transfer control to the end point of the do statement (thus ending iteration of the embedded statement), and a continue statement (The continue statement) may be used to transfer control to the end point of the embedded statement.

do如果语句可访问,则可以访问语句的嵌入语句 doThe embedded statement of a do statement is reachable if the do statement is reachable.

do如果以下至少一个条件为 true,则可以访问语句的结束点:The end point of a do statement is reachable if at least one of the following is true:

  • do语句包含可访问语句 break ,该语句可退出 do 语句。The do statement contains a reachable break statement that exits the do statement.
  • 嵌入语句的结束点是可访问的,并且布尔表达式没有常数值 trueThe end point of the embedded statement is reachable and the boolean expression does not have the constant value true.

For 语句The for statement

for 语句计算一系列的初始化表达式,然后,当条件为 true 时,重复执行嵌入语句并计算迭代表达式的序列。The for statement evaluates a sequence of initialization expressions and then, while a condition is true, repeatedly executes an embedded statement and evaluates a sequence of iteration expressions.

for_statement
    : 'for' '(' for_initializer? ';' for_condition? ';' for_iterator? ')' embedded_statement
    ;

for_initializer
    : local_variable_declaration
    | statement_expression_list
    ;

for_condition
    : boolean_expression
    ;

for_iterator
    : statement_expression_list
    ;

statement_expression_list
    : statement_expression (',' statement_expression)*
    ;

For_initializer(如果存在)包含 local_variable_declaration (局部变量声明) 或 statement_expression () 表达式语句的列表,以逗号分隔。The for_initializer, if present, consists of either a local_variable_declaration (Local variable declarations) or a list of statement_expression s (Expression statements) separated by commas. For_initializer 声明的局部变量的作用域从变量的 local_variable_declarator 开始,并延伸到嵌入语句的末尾。The scope of a local variable declared by a for_initializer starts at the local_variable_declarator for the variable and extends to the end of the embedded statement. 范围包括 for_conditionfor_iteratorThe scope includes the for_condition and the for_iterator.

For_condition(如果存在)必须是) (布尔表达式boolean_expressionThe for_condition, if present, must be a boolean_expression (Boolean expressions).

For_iterator(如果存在)由 Statement_expression s (表达式语句的列表) 用逗号分隔。The for_iterator, if present, consists of a list of statement_expression s (Expression statements) separated by commas.

For 语句的执行方式如下:A for statement is executed as follows:

  • 如果 for_initializer 存在,变量初始值设定项或语句表达式将按照它们的写入顺序执行。If a for_initializer is present, the variable initializers or statement expressions are executed in the order they are written. 此步骤只执行一次。This step is only performed once.
  • 如果 for_condition 存在,则将对其进行计算。If a for_condition is present, it is evaluated.
  • 如果 for_condition 不存在,或者如果计算得到,则 true 控制被传输到嵌入语句。If the for_condition is not present or if the evaluation yields true, control is transferred to the embedded statement. 当和如果控件到达嵌入语句的结束点 (可能来自语句) 的执行时,将 continue 按顺序计算 for_iterator 的表达式(如果有),然后执行另一次迭代,从对上述步骤中的 for_condition 的求值开始。When and if control reaches the end point of the embedded statement (possibly from execution of a continue statement), the expressions of the for_iterator, if any, are evaluated in sequence, and then another iteration is performed, starting with evaluation of the for_condition in the step above.
  • 如果 for_condition 存在并且计算生成 false ,则控制将转移到语句的终结点 forIf the for_condition is present and the evaluation yields false, control is transferred to the end point of the for statement.

在语句的嵌入语句内 forbreak (break 语句的语句) 可用于将控制转移到语句的终结点 for (进而结束嵌入语句的迭代) ,并且 (continue continue 语句) 的语句可用于将控制转移到嵌入语句的终结点 (因此,从 for_iterator for_condition 开始,执行 ) 并执行语句的另一次迭代 forWithin the embedded statement of a for statement, a break statement (The break statement) may be used to transfer control to the end point of the for statement (thus ending iteration of the embedded statement), and a continue statement (The continue statement) may be used to transfer control to the end point of the embedded statement (thus executing the for_iterator and performing another iteration of the for statement, starting with the for_condition).

for如果满足以下条件之一,则可以访问语句的嵌入语句:The embedded statement of a for statement is reachable if one of the following is true:

  • for语句可访问,无 for_conditionThe for statement is reachable and no for_condition is present.
  • for 语句是可访问的,并且 for_condition 存在并且没有常数值 falseThe for statement is reachable and a for_condition is present and does not have the constant value false.

for如果以下至少一个条件为 true,则可以访问语句的结束点:The end point of a for statement is reachable if at least one of the following is true:

  • for语句包含可访问语句 break ,该语句可退出 for 语句。The for statement contains a reachable break statement that exits the for statement.
  • for 语句是可访问的,并且 for_condition 存在并且没有常数值 trueThe for statement is reachable and a for_condition is present and does not have the constant value true.

Foreach 语句The foreach statement

foreach语句枚举集合中的元素,并对集合中的每个元素执行嵌入语句。The foreach statement enumerates the elements of a collection, executing an embedded statement for each element of the collection.

foreach_statement
    : 'foreach' '(' local_variable_type identifier 'in' expression ')' embedded_statement
    ;

语句的 类型标识符 foreach 声明语句的 *迭代变量 _。The type and identifier of a foreach statement declare the *iteration variable _ of the statement. 如果 var 标识符指定为 _local_variable_type *,并且没有任何名为的类型 var 在范围内,则将迭代变量称为 隐式类型的迭代变量,并将其类型当作语句的元素类型 foreach ,如下所示。If the var identifier is given as the _local_variable_type*, and no type named var is in scope, the iteration variable is said to be an implicitly typed iteration variable, and its type is taken to be the element type of the foreach statement, as specified below. 迭代变量对应于一个只读局部变量,该局部变量具有扩展到嵌入语句的范围。The iteration variable corresponds to a read-only local variable with a scope that extends over the embedded statement. 在语句执行过程中 foreach ,迭代变量表示当前正在为其执行迭代的集合元素。During execution of a foreach statement, the iteration variable represents the collection element for which an iteration is currently being performed. 如果嵌入的语句尝试通过赋值或和) 运算符来修改迭代变量 (,则会发生编译时错误,或将 ++ -- 迭代变量作为 ref 或参数传递 outA compile-time error occurs if the embedded statement attempts to modify the iteration variable (via assignment or the ++ and -- operators) or pass the iteration variable as a ref or out parameter.

在下面的中,为简洁起见,、 IEnumerable IEnumerator IEnumerable<T>IEnumerator<T> 引用命名空间和中的相应 System.Collections 类型 System.Collections.GenericIn the following, for brevity, IEnumerable, IEnumerator, IEnumerable<T> and IEnumerator<T> refer to the corresponding types in the namespaces System.Collections and System.Collections.Generic.

Foreach 语句的编译时处理首先确定表达式的 集合类型 _、 _枚举器类型*_ 和 _ *元素类型**。The compile-time processing of a foreach statement first determines the collection type _, _enumerator type_ and _ element type of the expression. 这种决定将按如下方式进行:This determination proceeds as follows:

  • 如果表达式的 X 类型是数组类型,则从到接口 (存在隐式引用转换, X IEnumerable 因为 System.Array) 实现此接口。If the type X of expression is an array type then there is an implicit reference conversion from X to the IEnumerable interface (since System.Array implements this interface). 集合类型 _ 是 IEnumerable 接口, _枚举器类型_ 为 IEnumerator 接口,_ 元素类型 是数组类型的元素类型 XThe collection type _ is the IEnumerable interface, the _enumerator type_ is the IEnumerator interface and the _ element type is the element type of the array type X.

  • 如果表达式的 X 类型为,则 dynamicexpression 到 Interface 的隐式转换 IEnumerable (隐式动态转换) 。If the type X of expression is dynamic then there is an implicit conversion from expression to the IEnumerable interface (Implicit dynamic conversions). 集合类型 _ 是 IEnumerable 接口,而 _枚举器类型*_ 是 IEnumerator 接口。The collection type _ is the IEnumerable interface and the _enumerator type*_ is the IEnumerator interface. 如果将 var 标识符作为 _local_variable_type * 提供,则 元素类型dynamic ,否则为 objectIf the var identifier is given as the _local_variable_type* then the element type is dynamic, otherwise it is object.

  • 否则,请确定该类型是否 X 具有适当的 GetEnumerator 方法:Otherwise, determine whether the type X has an appropriate GetEnumerator method:

    • X 具有标识符 GetEnumerator 且无类型参数的类型执行成员查找。Perform member lookup on the type X with identifier GetEnumerator and no type arguments. 如果成员查找不会生成匹配项,或者它产生了多义性,或者产生了不是方法组的匹配项,请检查可枚举的接口,如下所述。If the member lookup does not produce a match, or it produces an ambiguity, or produces a match that is not a method group, check for an enumerable interface as described below. 如果成员查找产生了除方法组以外的任何内容,则建议发出警告。It is recommended that a warning be issued if member lookup produces anything except a method group or no match.
    • 使用生成的方法组和空参数列表执行重载决策。Perform overload resolution using the resulting method group and an empty argument list. 如果重载决策导致没有适用的方法、导致歧义或产生单个最佳方法,但该方法是静态的或非公共的,请按如下所述检查可枚举的接口。If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for an enumerable interface as described below. 如果重载决策产生了除明确的公共实例方法之外的任何内容,或者没有适用方法,则建议发出警告。It is recommended that a warning be issued if overload resolution produces anything except an unambiguous public instance method or no applicable methods.
    • 如果该方法的返回类型 E GetEnumerator 不是类、结构或接口类型,则会生成错误,并且不会执行任何其他步骤。If the return type E of the GetEnumerator method is not a class, struct or interface type, an error is produced and no further steps are taken.
    • 成员查找是在上 E 用标识符 Current 而不是类型参数执行的。Member lookup is performed on E with the identifier Current and no type arguments. 如果成员查找没有生成任何匹配项,则结果为错误,或结果为除允许读取的公共实例属性之外的任何内容,并不执行任何其他步骤。If the member lookup produces no match, the result is an error, or the result is anything except a public instance property that permits reading, an error is produced and no further steps are taken.
    • 成员查找是在上 E 用标识符 MoveNext 而不是类型参数执行的。Member lookup is performed on E with the identifier MoveNext and no type arguments. 如果成员查找没有生成任何匹配项,则结果为错误,或结果为除方法组外的任何内容,并不执行任何其他步骤。If the member lookup produces no match, the result is an error, or the result is anything except a method group, an error is produced and no further steps are taken.
    • 使用空参数列表对方法组执行重载决策。Overload resolution is performed on the method group with an empty argument list. 如果重载决策导致没有适用的方法,导致不确定性,或者导致单个最佳方法,但该方法是静态的或非公共的,或者它的返回类型不是 bool ,则会生成错误,并且不会执行任何其他步骤。If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, or its return type is not bool, an error is produced and no further steps are taken.
    • 集合类型 _ 是 X , _枚举器类型_ 为 E ,_ 元素类型 是属性的类型 CurrentThe collection type _ is X, the _enumerator type_ is E, and the _ element type is the type of the Current property.
  • 否则,请检查可枚举的接口:Otherwise, check for an enumerable interface:

    • 如果 Ti 存在从到的隐式转换到的所有类型 X IEnumerable<Ti> ,则有一个唯一类型,这种类型不适用, T T dynamic 并且对于所有其他类型的 Ti 隐式转换均 IEnumerable<T>IEnumerable<Ti> ,则 集合类型 _ 是接口 IEnumerable<T> , _枚举器类型_ 是接口 IEnumerator<T> ,而 _ 元素类型TIf among all the types Ti for which there is an implicit conversion from X to IEnumerable<Ti>, there is a unique type T such that T is not dynamic and for all the other Ti there is an implicit conversion from IEnumerable<T> to IEnumerable<Ti>, then the collection type _ is the interface IEnumerable<T>, the _enumerator type_ is the interface IEnumerator<T>, and the _ element type is T.
    • 否则,如果有多个这样的类型 T ,则会生成错误,并且不会执行任何其他步骤。Otherwise, if there is more than one such type T, then an error is produced and no further steps are taken.
    • 否则,如果存在从到接口的隐式转换 X System.Collections.IEnumerable ,则 集合类型 _ 是此接口, _枚举器类型_ 是接口 System.Collections.IEnumerator ,而 _ 元素类型objectOtherwise, if there is an implicit conversion from X to the System.Collections.IEnumerable interface, then the collection type _ is this interface, the _enumerator type_ is the interface System.Collections.IEnumerator, and the _ element type is object.
    • 否则,将生成错误,并且不执行任何其他步骤。Otherwise, an error is produced and no further steps are taken.

如果成功,上述步骤会明确产生集合类型 C 、枚举器类型 E 和元素类型 TThe above steps, if successful, unambiguously produce a collection type C, enumerator type E and element type T. 窗体的 foreach 语句A foreach statement of the form

foreach (V v in x) embedded_statement

然后扩展为:is then expanded to:

{
    E e = ((C)(x)).GetEnumerator();
    try {
        while (e.MoveNext()) {
            V v = (V)(T)e.Current;
            embedded_statement
        }
    }
    finally {
        ... // Dispose e
    }
}

变量对 e 表达式 x 或嵌入语句或程序的任何其他源代码都不可见或不可访问。The variable e is not visible to or accessible to the expression x or the embedded statement or any other source code of the program. 此变量 v 在嵌入语句中是只读的。The variable v is read-only in the embedded statement. 如果没有显式转换 () 从 T 元素类型) (到 (元素类型的显式转换 V , 则会生成错误,并且不会执行任何其他步骤。If there is not an explicit conversion (Explicit conversions) from T (the element type) to V (the local_variable_type in the foreach statement), an error is produced and no further steps are taken. 如果 x 具有值 nullSystem.NullReferenceException 则会在运行时引发。If x has the value null, a System.NullReferenceException is thrown at run-time.

允许实现以不同的方式实现给定的 foreach 语句(例如出于性能原因),前提是该行为与上述扩展一致。An implementation is permitted to implement a given foreach-statement differently, e.g. for performance reasons, as long as the behavior is consistent with the above expansion.

vWhile 循环内的位置对于在 embedded_statement 中发生的任何匿名函数如何捕获是非常重要的。The placement of v inside the while loop is important for how it is captured by any anonymous function occurring in the embedded_statement.

例如:For example:

int[] values = { 7, 9, 13 };
Action f = null;

foreach (var value in values)
{
    if (f == null) f = () => Console.WriteLine("First value: " + value);
}

f();

如果 v 是在 while 循环之外声明的,则会在所有迭代中共享该循环,而 for 循环之后它的值将是最终值, 13 这是对的调用将打印到的值 fIf v was declared outside of the while loop, it would be shared among all iterations, and its value after the for loop would be the final value, 13, which is what the invocation of f would print. 相反,因为每个迭代都有其自己的变量,所以, v f 第一次迭代中捕获的将继续保存值 7 ,这就是要打印的值。Instead, because each iteration has its own variable v, the one captured by f in the first iteration will continue to hold the value 7, which is what will be printed. (注意:在 while 循环之外声明的早期版本的 c # v 。 ) (Note: earlier versions of C# declared v outside of the while loop.)

Finally 块的主体按照以下步骤进行构造:The body of the finally block is constructed according to the following steps:

  • 如果存在从到接口的隐式转换 E System.IDisposable ,则If there is an implicit conversion from E to the System.IDisposable interface, then

    • 如果 E 是不可以为 null 的值类型,则将 finally 子句扩展为语义等效项:If E is a non-nullable value type then the finally clause is expanded to the semantic equivalent of:

      finally {
          ((System.IDisposable)e).Dispose();
      }
      
    • 否则,finally 子句将扩展到语义等效项:Otherwise the finally clause is expanded to the semantic equivalent of:

      finally {
          if (e != null) ((System.IDisposable)e).Dispose();
      }
      

    除了如果 E 是值类型或实例化为值类型的类型参数,的强制转换 e 不会 System.IDisposable 导致装箱发生。except that if E is a value type, or a type parameter instantiated to a value type, then the cast of e to System.IDisposable will not cause boxing to occur.

  • 否则,如果 E 是密封类型,则将 finally 子句扩展为空块:Otherwise, if E is a sealed type, the finally clause is expanded to an empty block:

    finally {
    }
    
  • 否则,finally 子句将扩展为:Otherwise, the finally clause is expanded to:

    finally {
        System.IDisposable d = e as System.IDisposable;
        if (d != null) d.Dispose();
    }
    

    本地变量 d 对任何用户代码都不可见或不可访问。The local variable d is not visible to or accessible to any user code. 具体而言,它不会与范围包含 finally 块的任何其他变量发生冲突。In particular, it does not conflict with any other variable whose scope includes the finally block.

foreach遍历数组元素的顺序如下:对于单维数组元素按递增的索引顺序进行遍历,从 index 开始,以  0 index 结束 Length - 1The order in which foreach traverses the elements of an array, is as follows: For single-dimensional arrays elements are traversed in increasing index order, starting with index 0 and ending with index Length - 1. 对于多维数组,会遍历元素,以便先增加最右侧维度的索引,然后再增加下一个左侧维度,依此类推。For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are increased first, then the next left dimension, and so on to the left.

下面的示例按元素顺序输出二维数组中的每个值:The following example prints out each value in a two-dimensional array, in element order:

using System;

class Test
{
    static void Main() {
        double[,] values = {
            {1.2, 2.3, 3.4, 4.5},
            {5.6, 6.7, 7.8, 8.9}
        };

        foreach (double elementValue in values)
            Console.Write("{0} ", elementValue);

        Console.WriteLine();
    }
}

生成的输出如下所示:The output produced is as follows:

1.2 2.3 3.4 4.5 5.6 6.7 7.8 8.9

示例中In the example

int[] numbers = { 1, 3, 5, 7, 9 };
foreach (var n in numbers) Console.WriteLine(n);

的类型 n 被推断为 int ,元素类型为 numbersthe type of n is inferred to be int, the element type of numbers.

跳转语句Jump statements

跳转语句无条件传输控制。Jump statements unconditionally transfer control.

jump_statement
    : break_statement
    | continue_statement
    | goto_statement
    | return_statement
    | throw_statement
    ;

跳转语句将控制转移到的位置称为跳转语句的 目标The location to which a jump statement transfers control is called the target of the jump statement.

如果跳转语句发生在块中,并且该跳转语句的目标在该块外,则可以使用跳转语句 退出 块。When a jump statement occurs within a block, and the target of that jump statement is outside that block, the jump statement is said to exit the block. 尽管一个跳转语句可以将控制转移到块外,但它永远不能将控制转移到块中。While a jump statement may transfer control out of a block, it can never transfer control into a block.

由于存在干预语句,跳转语句的执行很复杂 tryExecution of jump statements is complicated by the presence of intervening try statements. 在缺少此类语句的情况 try 下,跳转语句会无条件地将控制从跳转语句转移到其目标。In the absence of such try statements, a jump statement unconditionally transfers control from the jump statement to its target. 如果存在此类干预 try 语句,执行将更复杂。In the presence of such intervening try statements, execution is more complex. 如果跳转语句退出一个或多个 try 具有关联 finally 块的块,则控件最初会传输到 finally 最内层 try 语句的块。If the jump statement exits one or more try blocks with associated finally blocks, control is initially transferred to the finally block of the innermost try statement. 当和如果控件到达块的终点时 finally ,控制将被传输到 finally 下一个封闭语句的块 tryWhen and if control reaches the end point of a finally block, control is transferred to the finally block of the next enclosing try statement. 此过程将重复进行,直到 finally 执行了所有干预语句的块 tryThis process is repeated until the finally blocks of all intervening try statements have been executed.

示例中In the example

using System;

class Test
{
    static void Main() {
        while (true) {
            try {
                try {
                    Console.WriteLine("Before break");
                    break;
                }
                finally {
                    Console.WriteLine("Innermost finally block");
                }
            }
            finally {
                Console.WriteLine("Outermost finally block");
            }
        }
        Console.WriteLine("After break");
    }
}

finally try 控件传输到跳转语句的目标之前,将执行与两个语句关联的块。the finally blocks associated with two try statements are executed before control is transferred to the target of the jump statement.

生成的输出如下所示:The output produced is as follows:

Before break
Innermost finally block
Outermost finally block
After break

Break 语句The break statement

break语句退出最近的包含 switch 、、 while doforforeach 语句。The break statement exits the nearest enclosing switch, while, do, for, or foreach statement.

break_statement
    : 'break' ';'
    ;

语句的目标 break 是最近的封闭 switch 、、 while doforforeach 语句的终点。The target of a break statement is the end point of the nearest enclosing switch, while, do, for, or foreach statement. 如果 break 语句未由 switchwhile 、、或语句括起来 do ,则 for foreach 会发生编译时错误。If a break statement is not enclosed by a switch, while, do, for, or foreach statement, a compile-time error occurs.

当多个 switchwhiledoforforeach 语句彼此嵌套时, break 语句仅适用于最内层的语句。When multiple switch, while, do, for, or foreach statements are nested within each other, a break statement applies only to the innermost statement. 若要跨多个嵌套级别传输控制, goto 必须使用 goto 语句 (的 语句) 。To transfer control across multiple nesting levels, a goto statement (The goto statement) must be used.

break语句不能在 finally try 语句) (退出块。A break statement cannot exit a finally block (The try statement). break 语句在块中出现时 finally ,语句的目标 break 必须在同一块内 finally ; 否则,将发生编译时错误。When a break statement occurs within a finally block, the target of the break statement must be within the same finally block; otherwise, a compile-time error occurs.

break语句的执行方式如下:A break statement is executed as follows:

  • 如果 break 语句退出一个或多个 try 具有关联块的块 finally ,则控件最初会传输到 finally 最内层语句的块 tryIf the break statement exits one or more try blocks with associated finally blocks, control is initially transferred to the finally block of the innermost try statement. 当和如果控件到达块的终点时 finally ,控制将被传输到 finally 下一个封闭语句的块 tryWhen and if control reaches the end point of a finally block, control is transferred to the finally block of the next enclosing try statement. 此过程将重复进行,直到 finally 执行了所有干预语句的块 tryThis process is repeated until the finally blocks of all intervening try statements have been executed.
  • 控制将转移到语句的目标 breakControl is transferred to the target of the break statement.

由于 break 语句无条件地将控制转移到其他位置,因此 break 无法访问语句的结束点。Because a break statement unconditionally transfers control elsewhere, the end point of a break statement is never reachable.

Continue 语句The continue statement

continue语句启动最近的封闭 whiledofor 或语句的新迭代 foreachThe continue statement starts a new iteration of the nearest enclosing while, do, for, or foreach statement.

continue_statement
    : 'continue' ';'
    ;

语句的目标 continue 是最近的封闭 whiledofor 或语句的嵌入语句的终点 foreachThe target of a continue statement is the end point of the embedded statement of the nearest enclosing while, do, for, or foreach statement. 如果 continue 语句未由 whiledo 、或语句括起来 for ,则 foreach 会发生编译时错误。If a continue statement is not enclosed by a while, do, for, or foreach statement, a compile-time error occurs.

当多个 whiledoforforeach 语句彼此嵌套时, continue 语句仅适用于最内层的语句。When multiple while, do, for, or foreach statements are nested within each other, a continue statement applies only to the innermost statement. 若要跨多个嵌套级别传输控制, goto 必须使用 goto 语句 (的 语句) 。To transfer control across multiple nesting levels, a goto statement (The goto statement) must be used.

continue语句不能在 finally try 语句) (退出块。A continue statement cannot exit a finally block (The try statement). continue 语句在块中出现时 finally ,语句的目标 continue 必须在同一块内 finally ; 否则,将发生编译时错误。When a continue statement occurs within a finally block, the target of the continue statement must be within the same finally block; otherwise a compile-time error occurs.

continue语句的执行方式如下:A continue statement is executed as follows:

  • 如果 continue 语句退出一个或多个 try 具有关联块的块 finally ,则控件最初会传输到 finally 最内层语句的块 tryIf the continue statement exits one or more try blocks with associated finally blocks, control is initially transferred to the finally block of the innermost try statement. 当和如果控件到达块的终点时 finally ,控制将被传输到 finally 下一个封闭语句的块 tryWhen and if control reaches the end point of a finally block, control is transferred to the finally block of the next enclosing try statement. 此过程将重复进行,直到 finally 执行了所有干预语句的块 tryThis process is repeated until the finally blocks of all intervening try statements have been executed.
  • 控制将转移到语句的目标 continueControl is transferred to the target of the continue statement.

由于 continue 语句无条件地将控制转移到其他位置,因此 continue 无法访问语句的结束点。Because a continue statement unconditionally transfers control elsewhere, the end point of a continue statement is never reachable.

goto 语句The goto statement

goto语句将控制转移到由标签标记的语句。The goto statement transfers control to a statement that is marked by a label.

goto_statement
    : 'goto' identifier ';'
    | 'goto' 'case' constant_expression ';'
    | 'goto' 'default' ';'
    ;

goto标识符 语句的目标是带有给定标签的标记的语句。The target of a goto identifier statement is the labeled statement with the given label. 如果当前函数成员中不存在具有给定名称的标签,或者如果该 goto 语句不在标签范围内,则会发生编译时错误。If a label with the given name does not exist in the current function member, or if the goto statement is not within the scope of the label, a compile-time error occurs. 此规则允许使用 goto 语句将控制转移出嵌套作用域,而不是嵌套作用域。This rule permits the use of a goto statement to transfer control out of a nested scope, but not into a nested scope. 示例中In the example

using System;

class Test
{
    static void Main(string[] args) {
        string[,] table = {
            {"Red", "Blue", "Green"},
            {"Monday", "Wednesday", "Friday"}
        };

        foreach (string str in args) {
            int row, colm;
            for (row = 0; row <= 1; ++row)
                for (colm = 0; colm <= 2; ++colm)
                    if (str == table[row,colm])
                         goto done;

            Console.WriteLine("{0} not found", str);
            continue;
    done:
            Console.WriteLine("Found {0} at [{1}][{2}]", str, row, colm);
        }
    }
}

goto语句用于将控制转移出嵌套作用域。a goto statement is used to transfer control out of a nested scope.

语句的目标 goto caseswitch switch 语句) (的语句列表,其中包含 case 具有给定常数值的标签。The target of a goto case statement is the statement list in the immediately enclosing switch statement (The switch statement), which contains a case label with the given constant value. 如果 goto case 语句未包含在 switch 语句中,则如果 constant_expression 不能隐式转换 (将 隐式转换) 到最近的封闭语句的管理类型 switch ,或者最近的封闭 switch 语句不包含 case 具有给定常数值的标签,则会发生编译时错误。If the goto case statement is not enclosed by a switch statement, if the constant_expression is not implicitly convertible (Implicit conversions) to the governing type of the nearest enclosing switch statement, or if the nearest enclosing switch statement does not contain a case label with the given constant value, a compile-time error occurs.

语句的目标 goto defaultswitch (switch 语句) 的语句列表,它包含一个 default 标签。The target of a goto default statement is the statement list in the immediately enclosing switch statement (The switch statement), which contains a default label. 如果 goto default 语句未 switch 包含在语句内,或者最近的封闭语句不 switch 包含 default 标签,则会发生编译时错误。If the goto default statement is not enclosed by a switch statement, or if the nearest enclosing switch statement does not contain a default label, a compile-time error occurs.

goto语句不能在 finally try 语句) (退出块。A goto statement cannot exit a finally block (The try statement). goto 语句在块中出现时 finally ,语句的目标 goto 必须在同一块中 finally ,否则将发生编译时错误。When a goto statement occurs within a finally block, the target of the goto statement must be within the same finally block, or otherwise a compile-time error occurs.

goto语句的执行方式如下:A goto statement is executed as follows:

  • 如果 goto 语句退出一个或多个 try 具有关联块的块 finally ,则控件最初会传输到 finally 最内层语句的块 tryIf the goto statement exits one or more try blocks with associated finally blocks, control is initially transferred to the finally block of the innermost try statement. 当和如果控件到达块的终点时 finally ,控制将被传输到 finally 下一个封闭语句的块 tryWhen and if control reaches the end point of a finally block, control is transferred to the finally block of the next enclosing try statement. 此过程将重复进行,直到 finally 执行了所有干预语句的块 tryThis process is repeated until the finally blocks of all intervening try statements have been executed.
  • 控制将转移到语句的目标 gotoControl is transferred to the target of the goto statement.

由于 goto 语句无条件地将控制转移到其他位置,因此 goto 无法访问语句的结束点。Because a goto statement unconditionally transfers control elsewhere, the end point of a goto statement is never reachable.

Return 语句The return statement

return语句将控制权返回给出现该语句的函数的当前调用方 returnThe return statement returns control to the current caller of the function in which the return statement appears.

return_statement
    : 'return' expression? ';'
    ;

return 带 expression 的语句只能在不计算值的函数成员中使用,即,具有结果类型 (方法主体) 的方法 voidset 属性或索引器的访问器、事件的访问器、 add remove 实例构造函数、静态构造函数或析构函数。A return statement with no expression can be used only in a function member that does not compute a value, that is, a method with the result type (Method body) void, the set accessor of a property or indexer, the add and remove accessors of an event, an instance constructor, a static constructor, or a destructor.

return带有表达式的语句只能在计算值的函数成员中使用,即,具有非 void 结果类型的方法、 get 属性或索引器的访问器或用户定义的运算符。A return statement with an expression can only be used in a function member that computes a value, that is, a method with a non-void result type, the get accessor of a property or indexer, or a user-defined operator. 式转换 () 必须从表达式的类型转换为包含函数成员的返回类型。An implicit conversion (Implicit conversions) must exist from the type of the expression to the return type of the containing function member.

Return 语句还可用于 (匿名 函数表达式的匿名函数表达式的主体) ,并参与确定哪些转换存在这些函数。Return statements can also be used in the body of anonymous function expressions (Anonymous function expressions), and participate in determining which conversions exist for those functions.

return语句出现在 finally try 语句) (块中是编译时错误。It is a compile-time error for a return statement to appear in a finally block (The try statement).

return语句的执行方式如下:A return statement is executed as follows:

  • 如果该 return 语句指定一个表达式,将计算该表达式,并通过隐式转换将生成的值转换为包含函数的返回类型。If the return statement specifies an expression, the expression is evaluated and the resulting value is converted to the return type of the containing function by an implicit conversion. 转换的结果成为函数生成的结果值。The result of the conversion becomes the result value produced by the function.
  • 如果 return 语句由一个或多个 try catch 具有关联块的或块括起来,则 finally 控件最初将传输到 finally 最内层语句的块 tryIf the return statement is enclosed by one or more try or catch blocks with associated finally blocks, control is initially transferred to the finally block of the innermost try statement. 当和如果控件到达块的终点时 finally ,控制将被传输到 finally 下一个封闭语句的块 tryWhen and if control reaches the end point of a finally block, control is transferred to the finally block of the next enclosing try statement. 此过程将重复进行,直至 finally 所有封闭语句的块 try 都已执行完毕。This process is repeated until the finally blocks of all enclosing try statements have been executed.
  • 如果包含函数不是异步函数,则会将控件返回到包含函数的调用方,同时返回结果值(如果有)。If the containing function is not an async function, control is returned to the caller of the containing function along with the result value, if any.
  • 如果包含函数是一个异步函数,则将控制权返回给当前调用方,并在返回任务中记录结果值(如果有),如 (枚举器接口) 中所述。If the containing function is an async function, control is returned to the current caller, and the result value, if any, is recorded in the return task as described in (Enumerator interfaces).

由于 return 语句无条件地将控制转移到其他位置,因此 return 无法访问语句的结束点。Because a return statement unconditionally transfers control elsewhere, the end point of a return statement is never reachable.

Throw 语句The throw statement

throw语句引发异常。The throw statement throws an exception.

throw_statement
    : 'throw' expression? ';'
    ;

throw带有表达式的语句将引发通过计算表达式生成的值。A throw statement with an expression throws the value produced by evaluating the expression. 表达式必须表示 System.Exception 派生自或类型参数类型的类类型的值,该类型是 System.Exception 具有 (的类型形参类型, System.Exception 或是) 其有效基类的子类。The expression must denote a value of the class type System.Exception, of a class type that derives from System.Exception or of a type parameter type that has System.Exception (or a subclass thereof) as its effective base class. 如果表达式的计算结果为 nullSystem.NullReferenceException 则改为引发。If evaluation of the expression produces null, a System.NullReferenceException is thrown instead.

throw不带 expression 的语句只能用在 catch 块中,在这种情况下,该语句会重新引发该块当前正在处理的异常 catchA throw statement with no expression can be used only in a catch block, in which case that statement re-throws the exception that is currently being handled by that catch block.

由于 throw 语句无条件地将控制转移到其他位置,因此 throw 无法访问语句的结束点。Because a throw statement unconditionally transfers control elsewhere, the end point of a throw statement is never reachable.

当引发异常时,控制将被传输到 catch 可处理异常的封闭语句中的第一个子句 tryWhen an exception is thrown, control is transferred to the first catch clause in an enclosing try statement that can handle the exception. 从引发的异常点到将控件传输到适当的异常处理程序的时间点的过程称为 *异常传播 _。The process that takes place from the point of the exception being thrown to the point of transferring control to a suitable exception handler is known as *exception propagation . 异常的传播包括重复计算以下步骤,直到 catch 找到匹配该异常的子句。Propagation of an exception consists of repeatedly evaluating the following steps until a catch clause that matches the exception is found. 在此说明中, throw 点* 最初是引发异常的位置。In this description, the _ throw point* is initially the location at which the exception is thrown.

  • 在当前函数成员中, try 将检查包含引发点的每个语句。In the current function member, each try statement that encloses the throw point is examined. 对于每个语句 S ,从最内层的语句开始,到 try 最外面的 try 语句结束,计算以下步骤:For each statement S, starting with the innermost try statement and ending with the outermost try statement, the following steps are evaluated:

    • 如果 try 的块 S 包含一个或多个 catch 子句,则将 catch 按外观的顺序检查子句,以根据在 try 语句部分中指定的规则查找适用于异常的处理程序。If the try block of S encloses the throw point and if S has one or more catch clauses, the catch clauses are examined in order of appearance to locate a suitable handler for the exception, according to the rules specified in Section The try statement. 如果找到了匹配 catch 子句,则通过将控制转移到该子句的块来完成异常传播 catchIf a matching catch clause is located, the exception propagation is completed by transferring control to the block of that catch clause.

    • 否则,如果 try 块或 catchS 封闭了引发点,并且如果 Sfinally 块,则将控制转移到 finally 块。Otherwise, if the try block or a catch block of S encloses the throw point and if S has a finally block, control is transferred to the finally block. 如果 finally 该块引发另一个异常,则终止当前异常的处理。If the finally block throws another exception, processing of the current exception is terminated. 否则,当控件到达块的终点时 finally ,将继续处理当前异常。Otherwise, when control reaches the end point of the finally block, processing of the current exception is continued.

  • 如果在当前函数调用中未找到异常处理程序,则终止函数调用,并发生以下情况之一:If an exception handler was not located in the current function invocation, the function invocation is terminated, and one of the following occurs:

    • 如果当前函数为非异步,则会为函数调用方重复上述步骤,并将引发点与调用函数成员的语句对应。If the current function is non-async, the steps above are repeated for the caller of the function with a throw point corresponding to the statement from which the function member was invoked.

    • 如果当前函数为 async 并返回任务,则会在返回任务中记录异常,该异常将被置于 " 枚举器接口" 中所述的 "出错" 或 "已取消" 状态。If the current function is async and task-returning, the exception is recorded in the return task, which is put into a faulted or cancelled state as described in Enumerator interfaces.

    • 如果当前函数为 async 和 void 返回,则会通知当前线程的同步上下文,如可 枚举接口中所述。If the current function is async and void-returning, the synchronization context of the current thread is notified as described in Enumerable interfaces.

  • 如果异常处理终止当前线程中的所有函数成员调用,指示该线程没有异常的处理程序,则该线程本身将终止。If the exception processing terminates all function member invocations in the current thread, indicating that the thread has no handler for the exception, then the thread is itself terminated. 此类终止的影响是由实现定义的。The impact of such termination is implementation-defined.

Try 语句The try statement

try语句提供了一种机制,用于捕获在执行块期间发生的异常。The try statement provides a mechanism for catching exceptions that occur during execution of a block. 而且, try 语句提供了指定在控制离开语句时始终执行的代码块的能力 tryFurthermore, the try statement provides the ability to specify a block of code that is always executed when control leaves the try statement.

try_statement
    : 'try' block catch_clause+
    | 'try' block finally_clause
    | 'try' block catch_clause+ finally_clause
    ;

catch_clause
    : 'catch' exception_specifier? exception_filter?  block
    ;

exception_specifier
    : '(' type identifier? ')'
    ;

exception_filter
    : 'when' '(' expression ')'
    ;

finally_clause
    : 'finally' block
    ;

有三种可能的 try 语句形式:There are three possible forms of try statements:

  • try后跟一个或多个块的块 catchA try block followed by one or more catch blocks.
  • try后跟块的块 finallyA try block followed by a finally block.
  • try 跟一个或多个块 catch 后跟一个块的块 finallyA try block followed by one or more catch blocks followed by a finally block.

catch 子句指定 exception_specifier 时,类型必须为 System.Exception ,派生自的类型 System.ExceptionSystem.Exception (具有作为其有效基类) 的子类的类型形参类型。When a catch clause specifies an exception_specifier, the type must be System.Exception, a type that derives from System.Exception or a type parameter type that has System.Exception (or a subclass thereof) as its effective base class.

catch 子句同时指定带有 标识符exception_specifier 时,将声明给定名称和类型的 *异常变量 _。When a catch clause specifies both an exception_specifier with an identifier, an *exception variable _ of the given name and type is declared. 异常变量对应于具有扩展子句的作用域的局部变量 catchThe exception variable corresponds to a local variable with a scope that extends over the catch clause. 在 _exception_filter * 和 的执行期间,异常变量表示当前正在处理的异常。During execution of the _exception_filter* and block, the exception variable represents the exception currently being handled. 出于明确赋值检查的目的,在其整个范围内将异常变量视为明确赋值。For purposes of definite assignment checking, the exception variable is considered definitely assigned in its entire scope.

除非 catch 子句包含异常变量名称,否则无法访问筛选器和块中的异常对象 catchUnless a catch clause includes an exception variable name, it is impossible to access the exception object in the filter and catch block.

catch 指定 exception_specifier 的子句称为一般 catch 子句。A catch clause that does not specify an exception_specifier is called a general catch clause.

某些编程语言可能会支持不能表示为派生自的对象的异常 System.Exception ,尽管 c # 代码决不会生成此类异常。Some programming languages may support exceptions that are not representable as an object derived from System.Exception, although such exceptions could never be generated by C# code. catch可以使用常规子句来捕获此类异常。A general catch clause may be used to catch such exceptions. 因此,一般 catch 子句在语义上不同于指定类型的 System.Exception 规则,在这种情况下,前者还可以从其他语言中捕获异常。Thus, a general catch clause is semantically different from one that specifies the type System.Exception, in that the former may also catch exceptions from other languages.

为了定位异常的处理程序,按 catch 词法顺序检查子句。In order to locate a handler for an exception, catch clauses are examined in lexical order. 如果 catch 子句指定一个类型,但没有指定异常筛选器,则在同一语句中,后面的子句会出现编译时错误, catch try 以指定与该类型相同或派生自该类型的类型。If a catch clause specifies a type but no exception filter, it is a compile-time error for a later catch clause in the same try statement to specify a type that is the same as, or is derived from, that type. 如果 catch 子句未指定任何类型并且没有筛选器,则它必须是 catch 该语句的最后一个子句 tryIf a catch clause specifies no type and no filter, it must be the last catch clause for that try statement.

catch 块中, throw (throw 语句 的语句) 不包含表达式的语句可用于重新引发块捕获的异常 catchWithin a catch block, a throw statement (The throw statement) with no expression can be used to re-throw the exception that was caught by the catch block. 对异常变量的赋值不会改变重新引发的异常。Assignments to an exception variable do not alter the exception that is re-thrown.

示例中In the example

using System;

class Test
{
    static void F() {
        try {
            G();
        }
        catch (Exception e) {
            Console.WriteLine("Exception in F: " + e.Message);
            e = new Exception("F");
            throw;                // re-throw
        }
    }

    static void G() {
        throw new Exception("G");
    }

    static void Main() {
        try {
            F();
        }
        catch (Exception e) {
            Console.WriteLine("Exception in Main: " + e.Message);
        }
    }
}

方法 F 捕获异常,将一些诊断信息写入控制台,更改异常变量,并重新引发异常。the method F catches an exception, writes some diagnostic information to the console, alters the exception variable, and re-throws the exception. 重新引发的异常是原始异常,因此生成的输出为:The exception that is re-thrown is the original exception, so the output produced is:

Exception in F: G
Exception in Main: G

如果第一个 catch 块引发了 e 而不是重新引发当前异常,则生成的输出将如下所示:If the first catch block had thrown e instead of rethrowing the current exception, the output produced would be as follows:

Exception in F: G
Exception in Main: F

breakcontinuegoto 语句将控制传输到块的编译时错误 finallyIt is a compile-time error for a break, continue, or goto statement to transfer control out of a finally block. break continue goto 在块中发生、或语句时 finally ,语句的目标必须在同一 finally 块中,否则将发生编译时错误。When a break, continue, or goto statement occurs in a finally block, the target of the statement must be within the same finally block, or otherwise a compile-time error occurs.

return语句出现在块中是编译时错误 finallyIt is a compile-time error for a return statement to occur in a finally block.

try语句的执行方式如下:A try statement is executed as follows:

  • 控制传输到 try 块。Control is transferred to the try block.

  • 当和如果控件到达块的终结点时 tryWhen and if control reaches the end point of the try block:

    • 如果 try 语句有 finally 块,则 finally 执行块。If the try statement has a finally block, the finally block is executed.
    • 控制将转移到语句的终点 tryControl is transferred to the end point of the try statement.
  • 如果在执行块期间将异常传播到 try 语句 tryIf an exception is propagated to the try statement during execution of the try block:

    • catch子句(如果有)将按外观的顺序进行检查,以查找适用于异常的处理程序。The catch clauses, if any, are examined in order of appearance to locate a suitable handler for the exception. 如果 catch 子句未指定类型,或指定异常类型或异常类型的基类型,则为; 否则为。If a catch clause does not specify a type, or specifies the exception type or a base type of the exception type:
      • 如果 catch 子句声明了异常变量,则会将异常对象分配给异常变量。If the catch clause declares an exception variable, the exception object is assigned to the exception variable.
      • 如果 catch 子句声明了异常筛选器,则会计算筛选器。If the catch clause declares an exception filter, the filter is evaluated. 如果其计算结果为 false ,则 catch 子句不是匹配项,并且搜索将继续经过 catch 适用于适当处理程序的任何后续子句。If it evaluates to false, the catch clause is not a match, and the search continues through any subsequent catch clauses for a suitable handler.
      • 否则, catch 子句被视为匹配,并将控制转移到匹配的 catch 块。Otherwise, the catch clause is considered a match, and control is transferred to the matching catch block.
      • 当和如果控件到达块的终结点时 catchWhen and if control reaches the end point of the catch block:
        • 如果 try 语句有 finally 块,则 finally 执行块。If the try statement has a finally block, the finally block is executed.
        • 控制将转移到语句的终点 tryControl is transferred to the end point of the try statement.
      • 如果在执行块期间将异常传播到 try 语句 catchIf an exception is propagated to the try statement during execution of the catch block:
        • 如果 try 语句有 finally 块,则 finally 执行块。If the try statement has a finally block, the finally block is executed.
        • 异常将传播到下一个封闭 try 语句。The exception is propagated to the next enclosing try statement.
    • 如果 try 语句没有子句, catch 或者如果没有 catch 子句与异常匹配,则为:If the try statement has no catch clauses or if no catch clause matches the exception:
      • 如果 try 语句有 finally 块,则 finally 执行块。If the try statement has a finally block, the finally block is executed.
      • 异常将传播到下一个封闭 try 语句。The exception is propagated to the next enclosing try statement.

finally当控制离开语句时,始终会执行块的语句 tryThe statements of a finally block are always executed when control leaves a try statement. 无论是由于执行正常执行、、或语句导致控件传输还是由于将 break continue goto return 异常传播到 try 语句而导致的,都是如此。This is true whether the control transfer occurs as a result of normal execution, as a result of executing a break, continue, goto, or return statement, or as a result of propagating an exception out of the try statement.

如果在执行块期间引发了异常 finally ,并且未在同一个 finally 块中捕获该异常,则该异常将传播到下一个封闭 try 语句中。If an exception is thrown during execution of a finally block, and is not caught within the same finally block, the exception is propagated to the next enclosing try statement. 如果正在传播其他异常,则该异常将丢失。If another exception was in the process of being propagated, that exception is lost. 传播异常的过程在 throw (throw 语句) 的语句说明中进行了进一步讨论。The process of propagating an exception is discussed further in the description of the throw statement (The throw statement).

try try 如果语句可访问,则可以访问语句块 tryThe try block of a try statement is reachable if the try statement is reachable.

catch try 如果语句可访问,则可以访问语句块 tryA catch block of a try statement is reachable if the try statement is reachable.

finally try 如果语句可访问,则可以访问语句块 tryThe finally block of a try statement is reachable if the try statement is reachable.

try如果以下两个条件均为 true,则可以访问语句的终结点:The end point of a try statement is reachable if both of the following are true:

  • 块的终结点 try 是可访问的,或者至少有一个 catch 块可访问的终结点。The end point of the try block is reachable or the end point of at least one catch block is reachable.
  • 如果 finally 存在块,则可到达块的终结点 finallyIf a finally block is present, the end point of the finally block is reachable.

checked 和 unchecked 语句The checked and unchecked statements

checkedunchecked 语句用于控制整型算术运算和转换的 溢出检查上下文The checked and unchecked statements are used to control the overflow checking context for integral-type arithmetic operations and conversions.

checked_statement
    : 'checked' block
    ;

unchecked_statement
    : 'unchecked' block
    ;

checked语句导致在已检查的上下文中计算 中的所有表达式, unchecked 语句导致在未检查的上下文中计算 中的所有表达式。The checked statement causes all expressions in the block to be evaluated in a checked context, and the unchecked statement causes all expressions in the block to be evaluated in an unchecked context.

checkedunchecked 语句完全等效于 checked unchecked) 选中和未选中的运算符 (的和运算符,只不过它们在块而不是表达式上操作。The checked and unchecked statements are precisely equivalent to the checked and unchecked operators (The checked and unchecked operators), except that they operate on blocks instead of expressions.

lock 语句The lock statement

lock语句获取给定对象的互斥锁,执行语句,然后释放该锁。The lock statement obtains the mutual-exclusion lock for a given object, executes a statement, and then releases the lock.

lock_statement
    : 'lock' '(' expression ')' embedded_statement
    ;

语句的表达式 lock 必须表示已知为 reference_type 的类型的值。The expression of a lock statement must denote a value of a type known to be a reference_type. 没有对语句的表达式执行的 装箱) 转换 (进行隐式装箱转换 lock ,因此,表达式会出现编译时错误,指示 value_type 的值。No implicit boxing conversion (Boxing conversions) is ever performed for the expression of a lock statement, and thus it is a compile-time error for the expression to denote a value of a value_type.

lock窗体的语句A lock statement of the form

lock (x) ...

其中 xreference_type 的表达式,它完全等效于where x is an expression of a reference_type, is precisely equivalent to

bool __lockWasTaken = false;
try {
    System.Threading.Monitor.Enter(x, ref __lockWasTaken);
    ...
}
finally {
    if (__lockWasTaken) System.Threading.Monitor.Exit(x);
}

不同的是 x 只计算一次。except that x is only evaluated once.

持有互斥锁时,在同一执行线程中执行的代码也可以获取和释放锁。While a mutual-exclusion lock is held, code executing in the same execution thread can also obtain and release the lock. 但是,在其他线程中执行的代码被阻止获取锁定,直到锁定被释放。However, code executing in other threads is blocked from obtaining the lock until the lock is released.

System.Type不建议锁定对象以同步对静态数据的访问。Locking System.Type objects in order to synchronize access to static data is not recommended. 其他代码可能会锁定同一类型,这可能会导致死锁。Other code might lock on the same type, which can result in deadlock. 更好的方法是通过锁定专用静态对象来同步对静态数据的访问。A better approach is to synchronize access to static data by locking a private static object. 例如:For example:

class Cache
{
    private static readonly object synchronizationObject = new object();

    public static void Add(object x) {
        lock (Cache.synchronizationObject) {
            ...
        }
    }

    public static void Remove(object x) {
        lock (Cache.synchronizationObject) {
            ...
        }
    }
}

using 语句The using statement

using语句获取一个或多个资源,执行语句,然后释放资源。The using statement obtains one or more resources, executes a statement, and then disposes of the resource.

using_statement
    : 'using' '(' resource_acquisition ')' embedded_statement
    ;

resource_acquisition
    : local_variable_declaration
    | expression
    ;

资源 是实现的类或结构 System.IDisposable ,其中包括一个名为的无参数方法 DisposeA resource is a class or struct that implements System.IDisposable, which includes a single parameterless method named Dispose. 使用资源的代码可以调用 Dispose 来指示不再需要资源。Code that is using a resource can call Dispose to indicate that the resource is no longer needed. 如果 Dispose 未调用,则最终将作为垃圾回收的结果发生。If Dispose is not called, then automatic disposal eventually occurs as a consequence of garbage collection.

如果 local_variable_declaration resource_acquisition 的形式,则 local_variable_declaration 的类型必须为 dynamic 或可隐式转换为的类型 System.IDisposableIf the form of resource_acquisition is local_variable_declaration then the type of the local_variable_declaration must be either dynamic or a type that can be implicitly converted to System.IDisposable. 如果 resource_acquisition 的形式为 expression ,则此表达式必须可隐式转换为 System.IDisposableIf the form of resource_acquisition is expression then this expression must be implicitly convertible to System.IDisposable.

resource_acquisition 中声明的局部变量是只读的,并且必须包含初始值设定项。Local variables declared in a resource_acquisition are read-only, and must include an initializer. 如果嵌入的语句尝试通过赋值或和运算符) 修改这些本地 (变量,则会发生编译时错误,请 ++ -- 获取它们的地址,或将它们作为 refout 参数传递。A compile-time error occurs if the embedded statement attempts to modify these local variables (via assignment or the ++ and -- operators) , take the address of them, or pass them as ref or out parameters.

using语句转换为三个部分:获取、使用和处理。A using statement is translated into three parts: acquisition, usage, and disposal. 资源的使用隐式包含在 try 包含子句的语句中 finallyUsage of the resource is implicitly enclosed in a try statement that includes a finally clause. finally 子句处置资源。This finally clause disposes of the resource. 如果 null 已获取资源,则不会对进行任何调用 Dispose ,也不会引发异常。If a null resource is acquired, then no call to Dispose is made, and no exception is thrown. 如果资源的类型为, dynamic 则它会通过隐式动态转换动态转换, (在获取过程中) 到 隐式动态 转换, IDisposable 以确保转换在使用和处置之前成功。If the resource is of type dynamic it is dynamically converted through an implicit dynamic conversion (Implicit dynamic conversions) to IDisposable during acquisition in order to ensure that the conversion is successful before the usage and disposal.

using窗体的语句A using statement of the form

using (ResourceType resource = expression) statement

对应于三个可能的扩展中的一个。corresponds to one of three possible expansions. 如果 ResourceType 是不可以为 null 的值类型,则扩展为When ResourceType is a non-nullable value type, the expansion is

{
    ResourceType resource = expression;
    try {
        statement;
    }
    finally {
        ((IDisposable)resource).Dispose();
    }
}

否则,如果 ResourceType 是可以为 null 的值类型或引用类型(而不是 dynamic ),则扩展为Otherwise, when ResourceType is a nullable value type or a reference type other than dynamic, the expansion is

{
    ResourceType resource = expression;
    try {
        statement;
    }
    finally {
        if (resource != null) ((IDisposable)resource).Dispose();
    }
}

否则,如果 ResourceTypedynamic ,则扩展为Otherwise, when ResourceType is dynamic, the expansion is

{
    ResourceType resource = expression;
    IDisposable d = (IDisposable)resource;
    try {
        statement;
    }
    finally {
        if (d != null) d.Dispose();
    }
}

在任一扩展中, resource 变量在嵌入语句中是只读的,并且该 d 变量在嵌入的语句中不可访问,也不可见。In either expansion, the resource variable is read-only in the embedded statement, and the d variable is inaccessible in, and invisible to, the embedded statement.

允许实现以不同方式实现给定的 using 语句(例如出于性能原因),前提是该行为与上述扩展一致。An implementation is permitted to implement a given using-statement differently, e.g. for performance reasons, as long as the behavior is consistent with the above expansion.

using窗体的语句A using statement of the form

using (expression) statement

具有相同的三个可能的扩展。has the same three possible expansions. 在这种情况下 ResourceType ,将隐式的编译时类型 expression (如果有)。In this case ResourceType is implicitly the compile-time type of the expression, if it has one. 否则,接口 IDisposable 本身将用作 ResourceTypeOtherwise the interface IDisposable itself is used as the ResourceType. resource 变量在嵌入的语句中不可访问,也不可见。The resource variable is inaccessible in, and invisible to, the embedded statement.

如果 resource_acquisition 采用 local_variable_declaration 的形式,则可以获取给定类型的多个资源。When a resource_acquisition takes the form of a local_variable_declaration, it is possible to acquire multiple resources of a given type. using窗体的语句A using statement of the form

using (ResourceType r1 = e1, r2 = e2, ..., rN = eN) statement

完全等效于一系列嵌套 using 语句:is precisely equivalent to a sequence of nested using statements:

using (ResourceType r1 = e1)
    using (ResourceType r2 = e2)
        ...
            using (ResourceType rN = eN)
                statement

下面的示例创建一个名为的文件 log.txt ,并向该文件写入两行文本。The example below creates a file named log.txt and writes two lines of text to the file. 然后,该示例将打开该文件以进行读取,并将包含的文本行复制到控制台。The example then opens that same file for reading and copies the contained lines of text to the console.

using System;
using System.IO;

class Test
{
    static void Main() {
        using (TextWriter w = File.CreateText("log.txt")) {
            w.WriteLine("This is line one");
            w.WriteLine("This is line two");
        }

        using (TextReader r = File.OpenText("log.txt")) {
            string s;
            while ((s = r.ReadLine()) != null) {
                Console.WriteLine(s);
            }

        }
    }
}

由于 TextWriterTextReader 类实现 IDisposable 接口,因此该示例可以使用 using 语句来确保在写入或读取操作后正确关闭基础文件。Since the TextWriter and TextReader classes implement the IDisposable interface, the example can use using statements to ensure that the underlying file is properly closed following the write or read operations.

yield 语句The yield statement

yield在迭代器块中使用该语句 () 将值发送到枚举器对象 (枚举器对象) 或可枚举对象 (迭代器) 的可枚举对象,或指示迭代结束。The yield statement is used in an iterator block (Blocks) to yield a value to the enumerator object (Enumerator objects) or enumerable object (Enumerable objects) of an iterator or to signal the end of the iteration.

yield_statement
    : 'yield' 'return' expression ';'
    | 'yield' 'break' ';'
    ;

yield 不是保留字;仅当紧靠在或关键字之前使用时,它才具有特殊意义 return breakyield is not a reserved word; it has special meaning only when used immediately before a return or break keyword. 在其他上下文中, yield 可用作标识符。In other contexts, yield can be used as an identifier.

语句可以出现的位置有多个限制 yield ,如下所述。There are several restrictions on where a yield statement can appear, as described in the following.

  • 如果 yield 语句 (的语句) 出现在 method_bodyoperator_bodyaccessor_body 外,则这是编译时错误。It is a compile-time error for a yield statement (of either form) to appear outside a method_body, operator_body or accessor_body
  • 这是一个语句 (的编译时错误, yield) 会出现在匿名函数内。It is a compile-time error for a yield statement (of either form) to appear inside an anonymous function.
  • yield语句 (的语句) 出现在语句的子句中,这是编译时错误 finally tryIt is a compile-time error for a yield statement (of either form) to appear in the finally clause of a try statement.
  • yield return语句要出现在 try 包含任何子句的语句中的任何位置的编译时错误 catchIt is a compile-time error for a yield return statement to appear anywhere in a try statement that contains any catch clauses.

下面的示例显示了语句的一些有效和无效的用法 yieldThe following example shows some valid and invalid uses of yield statements.

delegate IEnumerable<int> D();

IEnumerator<int> GetEnumerator() {
    try {
        yield return 1;        // Ok
        yield break;           // Ok
    }
    finally {
        yield return 2;        // Error, yield in finally
        yield break;           // Error, yield in finally
    }

    try {
        yield return 3;        // Error, yield return in try...catch
        yield break;           // Ok
    }
    catch {
        yield return 4;        // Error, yield return in try...catch
        yield break;           // Ok
    }

    D d = delegate { 
        yield return 5;        // Error, yield in an anonymous function
    }; 
}

int MyMethod() {
    yield return 1;            // Error, wrong return type for an iterator block
}

式转换 () 必须从语句中表达式的类型 yield return 与迭代器的 Yield 类型 (yield 类型) 存在。An implicit conversion (Implicit conversions) must exist from the type of the expression in the yield return statement to the yield type (Yield type) of the iterator.

yield return语句的执行方式如下:A yield return statement is executed as follows:

  • 计算语句中给定的表达式,将其隐式转换为 yield 类型,并将其分配给 Current 枚举器对象的属性。The expression given in the statement is evaluated, implicitly converted to the yield type, and assigned to the Current property of the enumerator object.
  • 迭代器块的执行被挂起。Execution of the iterator block is suspended. 如果 yield return 语句在一个或多个 try 块中,则 finally 不会执行关联的块。If the yield return statement is within one or more try blocks, the associated finally blocks are not executed at this time.
  • MoveNext枚举器对象的方法返回 true 到其调用方,指示枚举数对象已成功地前进到下一项。The MoveNext method of the enumerator object returns true to its caller, indicating that the enumerator object successfully advanced to the next item.

对枚举器对象的方法的下一次调用 MoveNext 会从其上次挂起的位置继续执行迭代器块。The next call to the enumerator object's MoveNext method resumes execution of the iterator block from where it was last suspended.

yield break语句的执行方式如下:A yield break statement is executed as follows:

  • 如果 yield break 语句由一个或多个 try 具有关联块的块括起来 finally ,则控件最初会传输到 finally 最内层语句的块 tryIf the yield break statement is enclosed by one or more try blocks with associated finally blocks, control is initially transferred to the finally block of the innermost try statement. 当和如果控件到达块的终点时 finally ,控制将被传输到 finally 下一个封闭语句的块 tryWhen and if control reaches the end point of a finally block, control is transferred to the finally block of the next enclosing try statement. 此过程将重复进行,直至 finally 所有封闭语句的块 try 都已执行完毕。This process is repeated until the finally blocks of all enclosing try statements have been executed.
  • 控制权将返回给迭代器块的调用方。Control is returned to the caller of the iterator block. 这是 MoveNext Dispose 枚举器对象的方法或方法。This is either the MoveNext method or Dispose method of the enumerator object.

由于 yield break 语句无条件地将控制转移到其他位置,因此 yield break 无法访问语句的结束点。Because a yield break statement unconditionally transfers control elsewhere, the end point of a yield break statement is never reachable.