陳述式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.WriteLinethe 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連線到語句,因為可連線到第一個Console.WriteLine運算式語句的結束點。The if statement is reachable because the end point of the first Console.WriteLine expression statement is reachable.
  • 第二Console.WriteLine個運算式語句可以連接,因為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因為語句不允許參數區段「落到」下一個參數區段,所以參數區段之語句清單的結束點就會發生編譯時期錯誤。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 語句)的區塊稱為 iterator 區塊。A block that contains one or more yield statements (The yield statement) is called an iterator block. Iterator 區塊是用來將函式成員當做反覆運算器(反覆運算器)來執行。Iterator blocks are used to implement function members as iterators (Iterators). 有一些額外的限制適用于 iterator 區塊:Some additional restrictions apply to iterator blocks:

  • return語句會出現在 iterator 區塊中(但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. 語句清單會出現在區塊s (區塊)和switch_blocks (switch 語句)中。Statement lists occur in blocks (Blocks) and in switch_blocks (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.

如果下列至少一項為真,則語句清單中的語句可連線: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 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.

在撰寫while具有 null 主體的語句時,可以使用空的語句: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. 異常try try finally如果語句是在包含區塊的內,而且加上標籤的語句位於之外,而且無法連線到finally區塊的結束點,則無法從存取標記的語句gotogoto語句)。(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_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的清單,其中每個都會引進新的變數。The type is followed by a list of local_variable_declarators, 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_declarators。The local_variable_declaration cannot include multiple local_variable_declarators.
  • 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的清單,其中每個都會引進新的常數。The type is followed by a list of constant_declarators, each of which introduces a new constant. Constant_declarator包含命名常數的識別碼,後面接著 "=" token,接著是提供常數值的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
    ;

元件會與語法允許的最接近前面if的程式關聯。 elseAn 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. 當控制項到達該語句的結束點時,控制權就會傳送至if語句的結束點。When 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. 當控制項到達該語句的結束點時,控制權就會傳送至if語句的結束點。When and if control reaches the end point of that statement, control is transferred to the end point of the if statement.
  • 如果布林運算式產生false ,而且else如果元件不存在,控制權就會傳送至if語句的結束點。If 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語句,而且布林運算式沒有常數值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語句,而且布林運算式沒有常數值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連線到if語句,而且布林運算式else沒有常數值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 運算式值的相關聯參數標籤。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_sections, enclosed in braces. 每個switch_section都包含一個或多個switch_label,後面接著statement_list語句清單)。Each switch_section consists of one or more switch_labels followed by a statement_list (Statement lists).

switch語句的管理類型是由 switch 運算式所建立。The governing type of a switch statement is established by the switch expression.

  • 如果 switch 運算式的類型為 sbytebyteshortushortintuintlongulongboolchar、0 或enum_type,或者它是對應于其中一種類型的可為 null 的類型,那就是 2 語句的管理類型。If 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 運算式的類型,到下列其中一種可能的管理類型: sbytebyteshortushortintuint、 、longchar、或,這是對應至其中一種類型的可為 null 類型。 string ulongOtherwise, 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 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運算式的值,而且如果有標籤,則default會將控制權轉移至語句清單,並遵循標誌.If 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標籤,則控制權switch會傳送至語句的結束點。If 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.

如果可以連線到 switch 區段之語句清單的結束點,就會發生編譯時期錯誤。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 區段之後,執行另一個參數區段時,必須使用明確goto casegoto 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 區段的語句清單通常會在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 運算式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_blockstatement_list可能包含宣告語句(宣告語句)。The statement_lists 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 運算式是與 switch 區段中的case標籤相符的常數值。The switch expression is a constant value that matches a case label in the switch section.
  • Switch 運算式是不符合任何case標籤的常數值,而 switch 區段default包含標籤。The switch expression is a constant value that doesn't match any case label, and the switch section contains the default label.
  • Switch 區段的切換標籤是由goto case可連接的或goto default語句所參考。A switch label of the switch section is referenced by a reachable goto case or goto default statement.

如果下列至少一項switch為真,則語句的結束點可供連線:The end point of a switch statement is reachable if at least one of the following is true:

  • 語句包含可連接switchbreak語句,它會結束語句。 switchThe 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語句執行)時,控制權就會傳送至while語句的開頭。When 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,控制權就會傳送至while語句的結束點。If the boolean expression yields false, control is transferred to the end point of the while 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為真,則語句的結束點可供連線:The end point of a while statement is reachable if at least one of the following is true:

  • 語句包含可連接whilebreak語句,它會結束語句。 whileThe 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,控制權就會傳送至do語句的開頭。If the boolean expression yields true, control is transferred to the beginning of the do statement. 否則,控制權會轉移到do語句的結束點。Otherwise, control is transferred to the end point of the do 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為真,則語句的結束點可供連線:The end point of a do statement is reachable if at least one of the following is true:

  • 語句包含可連接dobreak語句,它會結束語句。 doThe 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_expressions (expression 語句)清單(以逗號分隔)所組成。The for_initializer, if present, consists of either a local_variable_declaration (Local variable declarations) or a list of statement_expressions (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_expression布林運算式)。The for_condition, if present, must be a boolean_expression (Boolean expressions).

For_iterator(如果有的話)包含以逗號分隔的Statement_expressions (expression 語句)清單。The for_iterator, if present, consists of a list of statement_expressions (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. 當控制項到達內嵌語句的結束點(可能是從執行 @no__t 0 的語句)時,會依序評估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,則控制權會轉移至 @no__t 2 語句的結束點。If the for_condition is present and the evaluation yields false, control is transferred to the end point of the for statement.

for 語句的 embedded 語句中,@no__t 1 語句(break 語句)可以用來將控制權轉移至 for 語句的結束點(因此,會結束內嵌語句的反復專案)和 continue 語句(Continue 語句)可用來將控制權轉移到內嵌語句的結束點(因此,從for_condition開始,執行for_iterator並執行 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:

  • @No__t-0 語句可供連線,而且沒有任何for_condition存在。The for statement is reachable and no for_condition is present.
  • @No__t-0 語句可供連線,而且有for_condition存在,而且沒有常數值 falseThe for statement is reachable and a for_condition is present and does not have the constant value false.

如果下列至少一項for為真,則語句的結束點可供連線:The end point of a for statement is reachable if at least one of the following is true:

  • 語句包含可連接forbreak語句,它會結束語句。 forThe for statement contains a reachable break statement that exits the for statement.
  • @No__t-0 語句可供連線,而且有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. 如果 @no__t 0 的識別碼指定為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.

在下列中,為了簡單起見IEnumerableIEnumerator IEnumerable<T> 、和IEnumerator<T>會參考命名空間System.CollectionsSystem.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類型是陣列類型,則會有從XIEnumerable介面的隱含參考轉換(因為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介面,而元素類型為數組類型X的元素類型。The 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類型 dynamic是,則會隱含地從運算式轉換成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:

    • 在具有識別碼GetEnumerator和沒有類型X引數的類型上執行成員查閱。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.
    • 如果GetEnumerator方法的傳回E型別不是類別、結構或介面型別,就會產生錯誤,而且不會採取任何進一步的步驟。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為, Current元素型別為屬性的型別。The 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>IEnumerator<T> IEnumerable<T>的隱含轉換,則集合類型為介面、列舉數值型別為介面,而元素類型為IEnumerable<Ti> T.If 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.
    • 否則,如果有XSystem.Collections.IEnumerable到介面的隱含轉換,則集合類型為此介面、列舉數值型別為介面System.Collections.IEnumerator,而元素類型object.Otherwise, 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 (foreach 語句中的local_variable_type )的明確轉換(明確轉換),就會產生錯誤,而且不會採取任何進一步的步驟。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.

While 迴圈內 v 的位置,對於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 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遍歷陣列元素的順序如下所示:對於一維陣列元素,會以遞增的索引順序來進行遍歷, 0從索引開始, 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會推斷intnumbers,其為的元素類型。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

for do switch while語句會結束最接近的封閉式、、、或foreach語句。 breakThe break statement exits the nearest enclosing switch, while, do, for, or foreach statement.

break_statement
    : 'break' ';'
    ;

break語句的目標是switch最接近之封入、 for while do、、或foreach語句的結束點。The target of a break statement is the end point of the nearest enclosing switch, while, do, for, or foreach statement. switch while如果語句不是for以、、 do、或foreach語句括住,就會發生編譯時期錯誤。 breakIf a break statement is not enclosed by a switch, while, do, for, or foreach statement, a compile-time error occurs.

當多switchwhile break 、、、或foreach語句彼此嵌套時,語句只會套用到最內層的語句。 do forWhen 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.

語句無法結束區塊(try 語句)。 finally breakA break statement cannot exit a finally block (The try statement). 當語句在區塊內發生時break ,語句的目標必須在相同finally的區塊內,否則會發生編譯時期錯誤。 finally breakWhen 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:

  • try finally finally try如果語句結束一個或多個具有相關聯區塊的區塊,則控制權一開始會傳送到最內層語句的區塊。 breakIf 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到下一個封入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.
  • 控制權會傳送至break語句的目標。Control is transferred to the target of the break statement.

因為語句會無條件地將控制權轉移到別處,所以永遠break無法連線到語句的結束點。 breakBecause a break statement unconditionally transfers control elsewhere, the end point of a break statement is never reachable.

Continue 語句The continue statement

do while foreach for語句會啟動最接近之封閉式、、或語句的新反復專案。 continueThe continue statement starts a new iteration of the nearest enclosing while, do, for, or foreach statement.

continue_statement
    : 'continue' ';'
    ;

continue語句的目標是最接近之封閉式whiledoforforeach語句之內嵌語句的結束點。The target of a continue statement is the end point of the embedded statement of the nearest enclosing while, do, for, or foreach statement. do for如果語句不是以while、、或foreach語句括住,就會發生編譯時期錯誤。 continueIf a continue statement is not enclosed by a while, do, for, or foreach statement, a compile-time error occurs.

當多whiledoforcontinueforeach語句彼此嵌套時,語句只會套用到最內層的語句。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.

語句無法結束區塊(try 語句)。 finally continueA continue statement cannot exit a finally block (The try statement). 當語句在區塊內發生時continue ,語句的目標必須在相同finally的區塊內,否則會發生編譯時期錯誤。 finally continueWhen 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:

  • try finally finally try如果語句結束一個或多個具有相關聯區塊的區塊,則控制權一開始會傳送到最內層語句的區塊。 continueIf 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到下一個封入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.
  • 控制權會傳送至continue語句的目標。Control is transferred to the target of the continue statement.

因為語句會無條件地將控制權轉移到別處,所以永遠continue無法連線到語句的結束點。 continueBecause 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' ';'
    ;

Identifier語句的目標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立即封入語句( case switch 語句)中的語句清單,其中包含具有給定常數值的標籤。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. 如果 @no__t 0 的語句不是以 @no__t 1 的語句括住,則為,如果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立即封入語句( default switch 語句)中的語句清單,其中包含標籤。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. 如果語句未以switch語句括住,或最接近的封閉式switch語句不包含default標籤,則會發生編譯時期錯誤。 goto defaultIf 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.

語句無法結束區塊(try 語句)。 finally gotoA goto statement cannot exit a finally block (The try statement). 當語句在區塊內發生時goto ,語句的目標必須在相同finally的區塊內,否則會發生編譯時期錯誤。 finally gotoWhen 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:

  • try finally finally try如果語句結束一個或多個具有相關聯區塊的區塊,則控制權一開始會傳送到最內層語句的區塊。 gotoIf 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到下一個封入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.
  • 控制權會傳送至goto語句的目標。Control is transferred to the target of the goto statement.

因為語句會無條件地將控制權轉移到別處,所以永遠goto無法連線到語句的結束點。 gotoBecause 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? ';'
    ;

add void set return沒有運算式的語句只能用在不會計算值的函式成員中,也就是具有結果類型(方法主體)的方法、屬性或索引子的存取子、事件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.

具有運算式的get 語句只能在計算值的函式成員中使用,也就是具有非void結果類型的方法、屬性或索引子的存取子,或使用者return定義的運算子。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.
  • finally catch try finally如果語句是以一或多個具有相關聯區塊的區塊括住,則控制項一開始會傳送到最try內層語句的區塊。 returnIf 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到下一個封入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 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無法連線到語句的結束點。 returnBecause 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? ';'
    ;

具有運算式的語句會擲回評估運算式所產生的值。 throwA 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.

沒有運算式的catch catch語句只能用在區塊中,在此情況下,語句會重新擲回該區塊目前正在處理的例外狀況。 throwA 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無法連線到語句的結束點。 throwBecause a throw statement unconditionally transfers control elsewhere, the end point of a throw statement is never reachable.

當擲回例外狀況時,控制權會傳送至封catchtry語句中可處理例外狀況的第一個子句。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. 在此描述中,擲回點是一開始擲回例外狀況的位置。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:

    • catch如果的try區塊包含擲回點,且如果有一或多個子句,則catch會依照外觀的順序檢查子句,以根據中指定的規則來尋找適當的例外狀況處理常式S一節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的子句,就會藉由將控制權轉移至該catch子句的區塊來完成例外狀況傳播。If a matching catch clause is located, the exception propagation is completed by transferring control to the block of that catch clause.

    • try否則,如果區塊catch或的S區塊包含擲回點,而且如果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.

    • 如果目前的函式為非同步和工作傳回,則會將例外狀況記錄在傳回工作中,此工作會放入「錯誤」或「已取消」狀態,如列舉值介面中所述。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區塊的區塊。A try block followed by one or more catch blocks.
  • 區塊後面接著finally區塊。 tryA try block followed by a finally block.
  • 後面接著一個或多個catch區塊finally的區塊,後面接著一個區塊。tryA try block followed by one or more catch blocks followed by a finally 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.

當 @no__t 0 子句同時指定具有識別碼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區塊中的例外狀況物件。 catchUnless a catch clause includes an exception variable name, it is impossible to access the exception object in the filter and catch block.

未指定exception_specifier的 @no__t 0 子句稱為一般的 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. General 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. 如果子句指定類型,但沒有例外狀況篩選準則,則在相同try語句中,後面catch的子句會發生編譯時期錯誤,以指定與該類型相同或衍生自的類型。 catchIf 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是該try語句的最後一個子句。 catchIf a catch clause specifies no type and no filter, it must be the last catch clause for that try statement.

在區塊內throw ,沒有運算式的語句(throw 語句)可以用來重新擲回catch區塊攔截到的例外狀況。 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

break、或finally continue語句將控制權轉移到區塊時,就會發生編譯時期錯誤。gotoIt is a compile-time error for a break, continue, or goto statement to transfer control out of a finally block. break當、 continue finally或語句出現在區塊中時,語句的目標必須在相同的區塊內,否則就會發生編譯時期錯誤。finally gotoWhen 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 the try block.

  • 當控制項到達try區塊的結束點時:When and if control reaches the end point of the try block:

    • 如果語句具有區塊,則會執行finally區塊。 finally tryIf the try statement has a finally block, the finally block is executed.
    • 控制權會傳送至try語句的結束點。Control is transferred to the end point of the try statement.
  • 如果在try區塊執行期間將例外try狀況傳播至語句:If 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.
      • 當控制項到達catch區塊的結束點時:When and if control reaches the end point of the catch block:
        • 如果語句具有區塊,則會執行finally區塊。 finally tryIf the try statement has a finally block, the finally block is executed.
        • 控制權會傳送至try語句的結束點。Control is transferred to the end point of the try statement.
      • 如果在catch區塊執行期間將例外try狀況傳播至語句:If an exception is propagated to the try statement during execution of the catch block:
        • 如果語句具有區塊,則會執行finally區塊。 finally tryIf the try statement has a finally block, the finally block is executed.
        • 例外狀況會傳播至下一個封閉式try語句。The exception is propagated to the next enclosing try statement.
    • 如果語句沒有子句,或如果沒有catch子句符合此例外狀況: catch tryIf the try statement has no catch clauses or if no catch clause matches the exception:
      • 如果語句具有區塊,則會執行finally區塊。 finally tryIf the try statement has a finally block, the finally block is executed.
      • 例外狀況會傳播至下一個封閉式try語句。The exception is propagated to the next enclosing try statement.

當控制項finally try離開語句時,一律會執行區塊的語句。The statements of a finally block are always executed when control leaves a try statement. 無論是因為執行breakcontinuegotoreturn語句而造成控制轉移,或是因為將例外狀況傳播到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都成立,就可以觸達語句的結束點: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

和語句是用來控制整數型別算數運算和轉換的溢位檢查內容。 checked uncheckedThe 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
    ;

語句會在檢查的unchecked內容中評估區塊中的所有運算式,而語句會導致區塊中的所有運算式在未檢查的內容中進行評估。 checkedThe 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相當于和unchecked運算子(checked 和 unchecked 運算子),不同之處在于它們會在區塊上運作,而不是運算式。 checkedThe 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
    ;

@No__t-0 語句的運算式必須代表已知為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.

表單的語句lockA 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,其中包含名為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.

如果resource_acquisition的格式為local_variable_declaration ,則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.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. 如果內嵌語句嘗試修改這些本機變數(透過指派++或和--運算子)、接受其位址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. 如果取得Dispose資源,則不會對進行呼叫,也不會擲回任何例外狀況。 nullIf 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.

表單的語句usingA 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.

表單的語句usingA using statement of the form

using (expression) statement

有三個可能的擴充。has the same three possible expansions. 在此情況ResourceTypeexpression,會隱含地編譯時間型別(如果有的話)。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. 在內嵌的語句中,變數無法在中存取,而且不會隱藏。resourceThe 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. 表單的語句usingA 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);
            }

        }
    }
}

IDisposable using由於和類別TextReader會實作為介面,因此此範例可以使用語句來確保基礎檔案在寫入或讀取作業之後正確地關閉。 TextWriterSince 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

語句會用於反覆運算器區塊(區塊),以產生反覆運算器的值給枚舉器物件(枚舉器物件)或可列舉物件(可列舉物件),或表示反復專案結束。yieldThe 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不是保留字;只有當緊接在returnbreak關鍵字之前使用時,它才有特殊意義。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.

  • method_bodyoperator_bodyaccessor_body外出現的 @no__t 0 語句(任一形式)時,會發生編譯時期錯誤。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 子句try (其中一種形式)會發生編譯時期錯誤。It is a compile-time error for a yield statement (of either form) to appear in the finally clause of a try statement.
  • yield return語句catch 出現try在包含任何子句之語句中的任何位置時,會發生編譯時期錯誤。It is a compile-time error for a yield return statement to appear anywhere in a try statement that contains any catch 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 類型)。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. 如果語句位於一個或多個try區塊內,此時不finally會執行相關聯的區塊。 yield returnIf the yield return statement is within one or more try blocks, the associated finally blocks are not executed at this time.
  • 列舉MoveNexttrue物件的方法會傳回其呼叫端,表示枚舉器物件已成功前進到下一個專案。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:

  • try finally finally try如果語句是以一或多個具有相關聯區塊的區塊括住,則控制項一開始會傳送到最內層語句的區塊。 yield breakIf 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到下一個封入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 enclosing try statements have been executed.
  • 控制項會傳回 iterator 區塊的呼叫端。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 breakBecause a yield break statement unconditionally transfers control elsewhere, the end point of a yield break statement is never reachable.