语句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. 在编译时计算常量表达式,生成值时 false
, Console.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 firstConsole.WriteLine
expression statement is reachable because the block of theF
method is reachable. - 第一个表达式语句的结束点是可访问的
Console.WriteLine
,因为该语句是可访问的。The end point of the firstConsole.WriteLine
expression statement is reachable because that statement is reachable. if
由于第一个 expression 语句的结束点Console.WriteLine
是可访问的,因此该语句是可访问的。Theif
statement is reachable because the end point of the firstConsole.WriteLine
expression statement is reachable.- 可访问第二个
Console.WriteLine
expression 语句,因为该语句的布尔表达式没有if
常数值false
。The secondConsole.WriteLine
expression statement is reachable because the boolean expression of theif
statement does not have the constant valuefalse
.
在以下两种情况下,可能会发生编译时错误,导致语句的终结点可到达: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 theswitch
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 abreak
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 areturn
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 areturn
statement to appear in an iterator block (butyield 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.
- 语句是标记的语句,并且标签由可访问的语句引用
goto
。The statement is a labeled statement and the label is referenced by a reachablegoto
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.
使用空的正文编写语句时,可以使用空语句 while
:An 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.
除了正常的控制流提供的可访问性外,如果标签由可访问的语句引用,则可以访问标记的语句 goto
。In 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_statement 。A 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_declaration 的 local_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_initializer 。A 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_declarator。The local_variable_declaration cannot include multiple local_variable_declarator s.
- Local_variable_declarator 必须包含 local_variable_initializer。The 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
部件与语法允许的上一个词法上最近的语句相关联 if
。An 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 yieldstrue
, control is transferred to the first embedded statement. 当和如果控件到达该语句的终点时,控制将被传输到语句的终结点if
。When and if control reaches the end point of that statement, control is transferred to the end point of theif
statement. - 如果布尔表达式的结果
false
为,并且else
存在某个部分,则将控制转移到第二个嵌入语句。If the boolean expression yieldsfalse
and if anelse
part is present, control is transferred to the second embedded statement. 当和如果控件到达该语句的终点时,控制将被传输到语句的终结点if
。When and if control reaches the end point of that statement, control is transferred to the end point of theif
statement. - 如果布尔表达式产生
false
并且如果某个else
部分不存在,则将控制转移到该语句的结束点if
。If the boolean expression yieldsfalse
and if anelse
part is not present, control is transferred to the end point of theif
statement.
if
如果 if
语句是可访问的并且布尔表达式不具有常数值,则可以访问语句的第一个嵌入语句 false
。The 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
语句是可访问的并且布尔表达式不具有常数值,则语句的第二个嵌入语句(如果有)是可访问的 true
。The 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
语句是可访问的并且布尔表达式不具有常数值,则可访问没有任何部分的语句的结束点 true
。In 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_block。A 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
string
或 enum_type,或者,如果它是对应于这些类型之一的可为 null 的类型,则为该语句的管理类型switch
。If the type of the switch expression issbyte
,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 theswitch
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
必须表示一个可隐式转换 (隐式转换) 到该语句的管理类型的值 switch
。The 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 表达式的值,则控制将转移到匹配的标签后面的语句列表中case
。If one of the constants specified in acase
label in the sameswitch
statement is equal to the value of the switch expression, control is transferred to the statement list following the matchedcase
label. - 如果在
case
同一语句的标签中指定的常量均switch
不等于 switch 表达式的值,并且如果default
有标签,则会将控制转移到标签后面的语句列表中default
。If none of the constants specified incase
labels in the sameswitch
statement is equal to the value of the switch expression, and if adefault
label is present, control is transferred to the statement list following thedefault
label. - 如果在
case
同一语句的标签中指定的常量均switch
不等于 switch 表达式的值,并且如果不default
存在任何标签,则会将控制转移到语句的终点switch
。If none of the constants specified incase
labels in the sameswitch
statement is equal to the value of the switch expression, and if nodefault
label is present, control is transferred to the end point of theswitch
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_section。The 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 + + 中的常见错误类 break
。The "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 部分的语句列表通常以 break
、 goto case
或 goto 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. 同样, throw
或 return
语句始终将控制转移到其他位置,而永远不会到达终结点。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
可以是类型 string
。The 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 节 case
。Like 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_block 的 statement_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 表达式是一个与开关部分中的标签匹配的常量值
case
。The switch expression is a constant value that matches acase
label in the switch section. - Switch 表达式是不与任何标签匹配的常数值
case
,并且开关部分包含default
标签。The switch expression is a constant value that doesn't match anycase
label, and the switch section contains thedefault
label. - 开关部分的开关标签由可访问的
goto case
或goto default
语句引用。A switch label of the switch section is referenced by a reachablegoto case
orgoto 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
语句。Theswitch
statement contains a reachablebreak
statement that exits theswitch
statement.- 该
switch
语句可访问,switch 表达式为非常量值,并且不default
存在任何标签。Theswitch
statement is reachable, the switch expression is a non-constant value, and nodefault
label is present. - 该
switch
语句是可访问的,switch 表达式是不与任何标签匹配的常数值case
,并且不default
存在任何标签。Theswitch
statement is reachable, the switch expression is a constant value that doesn't match anycase
label, and nodefault
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 yieldstrue
, control is transferred to the embedded statement. 当和如果控件到达嵌入语句的结束点 (可能来自语句) 的执行时continue
,控件将转移到语句的开头while
。When and if control reaches the end point of the embedded statement (possibly from execution of acontinue
statement), control is transferred to the beginning of thewhile
statement. - 如果布尔表达式产生
false
,控制将被传输到语句的结束点while
。If the boolean expression yieldsfalse
, control is transferred to the end point of thewhile
statement.
在语句的嵌入语句中 while
, break
(break 语句) 的语句可用于将控制转移到语句的终结点 while
(从而结束嵌入语句的结束迭代) ,并且 (continue
continue 语句) 的语句可用于将控制转移到嵌入语句的终结点 (从而) 执行语句的另一次迭代 while
。Within 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
语句是可访问的并且布尔表达式不具有常数值,则可以访问语句的嵌入语句 false
。The 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
语句。Thewhile
statement contains a reachablebreak
statement that exits thewhile
statement.- 该
while
语句可访问,且布尔表达式没有常数值true
。Thewhile
statement is reachable and the boolean expression does not have the constant valuetrue
.
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 acontinue
statement), the boolean_expression (Boolean expressions) is evaluated. 如果布尔表达式产生true
,控制将被传输到语句的开头do
。If the boolean expression yieldstrue
, control is transferred to the beginning of thedo
statement. 否则,控制将转移到语句的结束点do
。Otherwise, control is transferred to the end point of thedo
statement.
在语句的嵌入语句中 do
, break
(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
如果语句可访问,则可以访问语句的嵌入语句 do
。The 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
语句。Thedo
statement contains a reachablebreak
statement that exits thedo
statement.- 嵌入语句的结束点是可访问的,并且布尔表达式没有常数值
true
。The end point of the embedded statement is reachable and the boolean expression does not have the constant valuetrue
.
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_condition 和 for_iterator。The scope includes the for_condition and the for_iterator.
For_condition(如果存在)必须是) (布尔表达式的 boolean_expression 。The 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 yieldstrue
, 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 acontinue
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
,则控制将转移到语句的终结点for
。If the for_condition is present and the evaluation yieldsfalse
, control is transferred to the end point of thefor
statement.
在语句的嵌入语句内 for
, break
(break 语句的语句) 可用于将控制转移到语句的终结点 for
(进而结束嵌入语句的迭代) ,并且 (continue
continue 语句) 的语句可用于将控制转移到嵌入语句的终结点 (因此,从 for_iterator for_condition 开始,执行 ) 并执行语句的另一次迭代 for
。 Within 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_condition 。Thefor
statement is reachable and no for_condition is present.- 该
for
语句是可访问的,并且 for_condition 存在并且没有常数值false
。Thefor
statement is reachable and a for_condition is present and does not have the constant valuefalse
.
for
如果以下至少一个条件为 true,则可以访问语句的结束点:The end point of a for
statement is reachable if at least one of the following is true:
for
语句包含可访问语句break
,该语句可退出for
语句。Thefor
statement contains a reachablebreak
statement that exits thefor
statement.- 该
for
语句是可访问的,并且 for_condition 存在并且没有常数值true
。Thefor
statement is reachable and a for_condition is present and does not have the constant valuetrue
.
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
或参数传递 out
。A 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.Generic
。In 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 typeX
of expression is an array type then there is an implicit reference conversion fromX
to theIEnumerable
interface (sinceSystem.Array
implements this interface). 集合类型 _ 是IEnumerable
接口, _枚举器类型_ 为IEnumerator
接口,_ 元素类型 是数组类型的元素类型X
。The collection type _ is theIEnumerable
interface, the _enumerator type_ is theIEnumerator
interface and the _ element type is the element type of the array typeX
.如果表达式的
X
类型为,则dynamic
从 expression 到 Interface 的隐式转换IEnumerable
(隐式动态转换) 。If the typeX
of expression isdynamic
then there is an implicit conversion from expression to theIEnumerable
interface (Implicit dynamic conversions). 集合类型 _ 是IEnumerable
接口,而 _枚举器类型*_ 是IEnumerator
接口。The collection type _ is theIEnumerable
interface and the _enumerator type*_ is theIEnumerator
interface. 如果将var
标识符作为 _local_variable_type * 提供,则 元素类型 为dynamic
,否则为object
。If thevar
identifier is given as the _local_variable_type* then the element type isdynamic
, otherwise it isobject
.否则,请确定该类型是否
X
具有适当的GetEnumerator
方法:Otherwise, determine whether the typeX
has an appropriateGetEnumerator
method:- 对
X
具有标识符GetEnumerator
且无类型参数的类型执行成员查找。Perform member lookup on the typeX
with identifierGetEnumerator
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 typeE
of theGetEnumerator
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 onE
with the identifierCurrent
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 onE
with the identifierMoveNext
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 notbool
, an error is produced and no further steps are taken. - 集合类型 _ 是
X
, _枚举器类型_ 为E
,_ 元素类型 是属性的类型Current
。The collection type _ isX
, the _enumerator type_ isE
, and the _ element type is the type of theCurrent
property.
- 对
否则,请检查可枚举的接口:Otherwise, check for an enumerable interface:
- 如果
Ti
存在从到的隐式转换到的所有类型X
IEnumerable<Ti>
,则有一个唯一类型,这种类型不适用,T
T
dynamic
并且对于所有其他类型的Ti
隐式转换均IEnumerable<T>
为IEnumerable<Ti>
,则 集合类型 _ 是接口IEnumerable<T>
, _枚举器类型_ 是接口IEnumerator<T>
,而 _ 元素类型 是T
。If among all the typesTi
for which there is an implicit conversion fromX
toIEnumerable<Ti>
, there is a unique typeT
such thatT
is notdynamic
and for all the otherTi
there is an implicit conversion fromIEnumerable<T>
toIEnumerable<Ti>
, then the collection type _ is the interfaceIEnumerable<T>
, the _enumerator type_ is the interfaceIEnumerator<T>
, and the _ element type isT
. - 否则,如果有多个这样的类型
T
,则会生成错误,并且不会执行任何其他步骤。Otherwise, if there is more than one such typeT
, then an error is produced and no further steps are taken. - 否则,如果存在从到接口的隐式转换
X
System.Collections.IEnumerable
,则 集合类型 _ 是此接口, _枚举器类型_ 是接口System.Collections.IEnumerator
,而 _ 元素类型 是object
。Otherwise, if there is an implicit conversion fromX
to theSystem.Collections.IEnumerable
interface, then the collection type _ is this interface, the _enumerator type_ is the interfaceSystem.Collections.IEnumerator
, and the _ element type isobject
. - 否则,将生成错误,并且不执行任何其他步骤。Otherwise, an error is produced and no further steps are taken.
- 如果
如果成功,上述步骤会明确产生集合类型 C
、枚举器类型 E
和元素类型 T
。The 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
具有值 null
, System.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.
v
While 循环内的位置对于在 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
这是对的调用将打印到的值 f
。If 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 fromE
to theSystem.IDisposable
interface, then如果
E
是不可以为 null 的值类型,则将 finally 子句扩展为语义等效项:IfE
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 ifE
is a value type, or a type parameter instantiated to a value type, then the cast ofe
toSystem.IDisposable
will not cause boxing to occur.否则,如果
E
是密封类型,则将 finally 子句扩展为空块:Otherwise, ifE
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 variabled
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 - 1
。The 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
,元素类型为 numbers
。the 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.
由于存在干预语句,跳转语句的执行很复杂 try
。Execution 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
下一个封闭语句的块 try
。When 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 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
do
、 for
或 foreach
语句。The break
statement exits the nearest enclosing switch
, while
, do
, for
, or foreach
statement.
break_statement
: 'break' ';'
;
语句的目标 break
是最近的封闭 switch
、、 while
do
、 for
或 foreach
语句的终点。The target of a break
statement is the end point of the nearest enclosing switch
, while
, do
, for
, or foreach
statement. 如果 break
语句未由 switch
、 while
、、或语句括起来 do
,则 for
foreach
会发生编译时错误。If a break
statement is not enclosed by a switch
, while
, do
, for
, or foreach
statement, a compile-time error occurs.
当多个 switch
、 while
、 do
、 for
或 foreach
语句彼此嵌套时, 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
最内层语句的块try
。If thebreak
statement exits one or moretry
blocks with associatedfinally
blocks, control is initially transferred to thefinally
block of the innermosttry
statement. 当和如果控件到达块的终点时finally
,控制将被传输到finally
下一个封闭语句的块try
。When and if control reaches the end point of afinally
block, control is transferred to thefinally
block of the next enclosingtry
statement. 此过程将重复进行,直到finally
执行了所有干预语句的块try
。This process is repeated until thefinally
blocks of all interveningtry
statements have been executed. - 控制将转移到语句的目标
break
。Control is transferred to the target of thebreak
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
语句启动最近的封闭 while
、 do
、 for
或语句的新迭代 foreach
。The continue
statement starts a new iteration of the nearest enclosing while
, do
, for
, or foreach
statement.
continue_statement
: 'continue' ';'
;
语句的目标 continue
是最近的封闭 while
、 do
、 for
或语句的嵌入语句的终点 foreach
。The target of a continue
statement is the end point of the embedded statement of the nearest enclosing while
, do
, for
, or foreach
statement. 如果 continue
语句未由 while
、 do
、或语句括起来 for
,则 foreach
会发生编译时错误。If a continue
statement is not enclosed by a while
, do
, for
, or foreach
statement, a compile-time error occurs.
当多个 while
、 do
、 for
或 foreach
语句彼此嵌套时, 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
最内层语句的块try
。If thecontinue
statement exits one or moretry
blocks with associatedfinally
blocks, control is initially transferred to thefinally
block of the innermosttry
statement. 当和如果控件到达块的终点时finally
,控制将被传输到finally
下一个封闭语句的块try
。When and if control reaches the end point of afinally
block, control is transferred to thefinally
block of the next enclosingtry
statement. 此过程将重复进行,直到finally
执行了所有干预语句的块try
。This process is repeated until thefinally
blocks of all interveningtry
statements have been executed. - 控制将转移到语句的目标
continue
。Control is transferred to the target of thecontinue
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 case
是 switch
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 default
是 switch
(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
最内层语句的块try
。If thegoto
statement exits one or moretry
blocks with associatedfinally
blocks, control is initially transferred to thefinally
block of the innermosttry
statement. 当和如果控件到达块的终点时finally
,控制将被传输到finally
下一个封闭语句的块try
。When and if control reaches the end point of afinally
block, control is transferred to thefinally
block of the next enclosingtry
statement. 此过程将重复进行,直到finally
执行了所有干预语句的块try
。This process is repeated until thefinally
blocks of all interveningtry
statements have been executed. - 控制将转移到语句的目标
goto
。Control is transferred to the target of thegoto
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
语句将控制权返回给出现该语句的函数的当前调用方 return
。The return
statement returns control to the current caller of the function in which the return
statement appears.
return_statement
: 'return' expression? ';'
;
不 return
带 expression 的语句只能在不计算值的函数成员中使用,即,具有结果类型 (方法主体) 的方法 void
、 set
属性或索引器的访问器、事件的访问器、 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 thereturn
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
最内层语句的块try
。If thereturn
statement is enclosed by one or moretry
orcatch
blocks with associatedfinally
blocks, control is initially transferred to thefinally
block of the innermosttry
statement. 当和如果控件到达块的终点时finally
,控制将被传输到finally
下一个封闭语句的块try
。When and if control reaches the end point of afinally
block, control is transferred to thefinally
block of the next enclosingtry
statement. 此过程将重复进行,直至finally
所有封闭语句的块try
都已执行完毕。This process is repeated until thefinally
blocks of all enclosingtry
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. 如果表达式的计算结果为 null
, System.NullReferenceException
则改为引发。If evaluation of the expression produces null
, a System.NullReferenceException
is thrown instead.
throw
不带 expression 的语句只能用在 catch
块中,在这种情况下,该语句会重新引发该块当前正在处理的异常 catch
。A 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
可处理异常的封闭语句中的第一个子句 try
。When 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, eachtry
statement that encloses the throw point is examined. 对于每个语句S
,从最内层的语句开始,到try
最外面的try
语句结束,计算以下步骤:For each statementS
, starting with the innermosttry
statement and ending with the outermosttry
statement, the following steps are evaluated:如果
try
的块S
包含一个或多个catch
子句,则将catch
按外观的顺序检查子句,以根据在 try 语句部分中指定的规则查找适用于异常的处理程序。If thetry
block ofS
encloses the throw point and if S has one or morecatch
clauses, thecatch
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
子句,则通过将控制转移到该子句的块来完成异常传播catch
。If a matchingcatch
clause is located, the exception propagation is completed by transferring control to the block of thatcatch
clause.否则,如果
try
块或catch
块S
封闭了引发点,并且如果S
有finally
块,则将控制转移到finally
块。Otherwise, if thetry
block or acatch
block ofS
encloses the throw point and ifS
has afinally
block, control is transferred to thefinally
block. 如果finally
该块引发另一个异常,则终止当前异常的处理。If thefinally
block throws another exception, processing of the current exception is terminated. 否则,当控件到达块的终点时finally
,将继续处理当前异常。Otherwise, when control reaches the end point of thefinally
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
语句提供了指定在控制离开语句时始终执行的代码块的能力 try
。Furthermore, 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
后跟一个或多个块的块catch
。Atry
block followed by one or morecatch
blocks.try
后跟块的块finally
。Atry
block followed by afinally
block.- 后
try
跟一个或多个块catch
后跟一个块的块finally
。Atry
block followed by one or morecatch
blocks followed by afinally
block.
当 catch
子句指定 exception_specifier 时,类型必须为 System.Exception
,派生自的类型 System.Exception
或 System.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. 异常变量对应于具有扩展子句的作用域的局部变量 catch
。The 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
子句包含异常变量名称,否则无法访问筛选器和块中的异常对象 catch
。Unless 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
该语句的最后一个子句 try
。If a catch
clause specifies no type and no filter, it must be the last catch
clause for that try
statement.
在 catch
块中, throw
(throw 语句 的语句) 不包含表达式的语句可用于重新引发块捕获的异常 catch
。Within 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
break
、 continue
或 goto
语句将控制传输到块的编译时错误 finally
。It 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
语句出现在块中是编译时错误 finally
。It 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 thetry
block.当和如果控件到达块的终结点时
try
:When and if control reaches the end point of thetry
block:- 如果
try
语句有finally
块,则finally
执行块。If thetry
statement has afinally
block, thefinally
block is executed. - 控制将转移到语句的终点
try
。Control is transferred to the end point of thetry
statement.
- 如果
如果在执行块期间将异常传播到
try
语句try
:If an exception is propagated to thetry
statement during execution of thetry
block:catch
子句(如果有)将按外观的顺序进行检查,以查找适用于异常的处理程序。Thecatch
clauses, if any, are examined in order of appearance to locate a suitable handler for the exception. 如果catch
子句未指定类型,或指定异常类型或异常类型的基类型,则为; 否则为。If acatch
clause does not specify a type, or specifies the exception type or a base type of the exception type:- 如果
catch
子句声明了异常变量,则会将异常对象分配给异常变量。If thecatch
clause declares an exception variable, the exception object is assigned to the exception variable. - 如果
catch
子句声明了异常筛选器,则会计算筛选器。If thecatch
clause declares an exception filter, the filter is evaluated. 如果其计算结果为false
,则 catch 子句不是匹配项,并且搜索将继续经过catch
适用于适当处理程序的任何后续子句。If it evaluates tofalse
, the catch clause is not a match, and the search continues through any subsequentcatch
clauses for a suitable handler. - 否则,
catch
子句被视为匹配,并将控制转移到匹配的catch
块。Otherwise, thecatch
clause is considered a match, and control is transferred to the matchingcatch
block. - 当和如果控件到达块的终结点时
catch
:When and if control reaches the end point of thecatch
block:- 如果
try
语句有finally
块,则finally
执行块。If thetry
statement has afinally
block, thefinally
block is executed. - 控制将转移到语句的终点
try
。Control is transferred to the end point of thetry
statement.
- 如果
- 如果在执行块期间将异常传播到
try
语句catch
:If an exception is propagated to thetry
statement during execution of thecatch
block:- 如果
try
语句有finally
块,则finally
执行块。If thetry
statement has afinally
block, thefinally
block is executed. - 异常将传播到下一个封闭
try
语句。The exception is propagated to the next enclosingtry
statement.
- 如果
- 如果
- 如果
try
语句没有子句,catch
或者如果没有catch
子句与异常匹配,则为:If thetry
statement has nocatch
clauses or if nocatch
clause matches the exception:- 如果
try
语句有finally
块,则finally
执行块。If thetry
statement has afinally
block, thefinally
block is executed. - 异常将传播到下一个封闭
try
语句。The exception is propagated to the next enclosingtry
statement.
- 如果
finally
当控制离开语句时,始终会执行块的语句 try
。The 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
如果语句可访问,则可以访问语句块 try
。The try
block of a try
statement is reachable if the try
statement is reachable.
catch
try
如果语句可访问,则可以访问语句块 try
。A catch
block of a try
statement is reachable if the try
statement is reachable.
finally
try
如果语句可访问,则可以访问语句块 try
。The 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 thetry
block is reachable or the end point of at least onecatch
block is reachable. - 如果
finally
存在块,则可到达块的终结点finally
。If afinally
block is present, the end point of thefinally
block is reachable.
checked 和 unchecked 语句The checked and unchecked statements
checked
和 unchecked
语句用于控制整型算术运算和转换的 溢出检查上下文。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.
checked
和 unchecked
语句完全等效于 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) ...
其中 x
是 reference_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
,其中包括一个名为的无参数方法 Dispose
。A 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.IDisposable
。If 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.IDisposable
。If 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. 如果嵌入的语句尝试通过赋值或和运算符) 修改这些本地 (变量,则会发生编译时错误,请 ++
--
获取它们的地址,或将它们作为 ref
或 out
参数传递。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
包含子句的语句中 finally
。Usage 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();
}
}
否则,如果 ResourceType
为 dynamic
,则扩展为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
本身将用作 ResourceType
。Otherwise 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);
}
}
}
}
由于 TextWriter
和 TextReader
类实现 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
break
。yield
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_body、 operator_body 或 accessor_body 外,则这是编译时错误。It is a compile-time error for ayield
statement (of either form) to appear outside a method_body, operator_body or accessor_body - 这是一个语句 (的编译时错误,
yield
) 会出现在匿名函数内。It is a compile-time error for ayield
statement (of either form) to appear inside an anonymous function. yield
语句 (的语句) 出现在语句的子句中,这是编译时错误finally
try
。It is a compile-time error for ayield
statement (of either form) to appear in thefinally
clause of atry
statement.yield return
语句要出现在try
包含任何子句的语句中的任何位置的编译时错误catch
。It is a compile-time error for ayield return
statement to appear anywhere in atry
statement that contains anycatch
clauses.
下面的示例显示了语句的一些有效和无效的用法 yield
。The 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 theCurrent
property of the enumerator object. - 迭代器块的执行被挂起。Execution of the iterator block is suspended. 如果
yield return
语句在一个或多个try
块中,则finally
不会执行关联的块。If theyield return
statement is within one or moretry
blocks, the associatedfinally
blocks are not executed at this time. MoveNext
枚举器对象的方法返回true
到其调用方,指示枚举数对象已成功地前进到下一项。TheMoveNext
method of the enumerator object returnstrue
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
最内层语句的块try
。If theyield break
statement is enclosed by one or moretry
blocks with associatedfinally
blocks, control is initially transferred to thefinally
block of the innermosttry
statement. 当和如果控件到达块的终点时finally
,控制将被传输到finally
下一个封闭语句的块try
。When and if control reaches the end point of afinally
block, control is transferred to thefinally
block of the next enclosingtry
statement. 此过程将重复进行,直至finally
所有封闭语句的块try
都已执行完毕。This process is repeated until thefinally
blocks of all enclosingtry
statements have been executed. - 控制权将返回给迭代器块的调用方。Control is returned to the caller of the iterator block. 这是
MoveNext
Dispose
枚举器对象的方法或方法。This is either theMoveNext
method orDispose
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.