日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#6.0语言规范(八) 语句

發布時間:2024/1/17 C# 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#6.0语言规范(八) 语句 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C#提供了各種語句。大多數這些語句對于使用C和C ++編程的開發人員來說都很熟悉。

1 statement 2 : labeled_statement 3 | declaration_statement 4 | embedded_statement 5 ; 6 7 embedded_statement 8 : block 9 | empty_statement 10 | expression_statement 11 | selection_statement 12 | iteration_statement 13 | jump_statement 14 | try_statement 15 | checked_statement 16 | unchecked_statement 17 | lock_statement 18 | using_statement 19 | yield_statement 20 | embedded_statement_unsafe 21 ;

該embedded_statement非終結用于出現其他語句中的語句。使用embedded_statement而不是語句排除了在這些上下文中使用聲明語句和帶標簽的語句。這個例子

1 void F(bool b) { 2 if (b) 3 int i = 44; 4 }

導致編譯時錯誤,因為if語句需要embedded_statement而不是if分支的語句。如果允許此代碼,則會i聲明變量,但永遠不會使用它。但請注意,通過i在塊中放置聲明,該示例是有效的。

終點和可達性

每個陳述都有一個終點。直觀地說,語句的結束點是緊跟語句的位置。復合語句(包含嵌入語句的語句)的執行規則指定控件到達嵌入語句的結束點時所采取的操作。例如,當控件到達塊中語句的結束點時,控制權將轉移到塊中的下一個語句。

如果可以通過執行來達到語句,則說該語句是可訪問的。相反,如果不可能執行語句,則說該語句無法訪問。

在這個例子中

1 void F() { 2 Console.WriteLine("reachable"); 3 goto Label; 4 Console.WriteLine("unreachable"); 5 Label: 6 Console.WriteLine("reachable"); 7 }

第二次調用Console.WriteLine是無法訪問的,因為不可能執行該語句。

如果編譯器確定語句無法訪問,則會報告警告。聲明無法訪問并不是錯誤。

要確定特定語句或端點是否可訪問,編譯器將根據為每個語句定義的可訪問性規則執行流分析。流分析考慮了控制語句行為的常量表達式(常量表達式)的值,但不考慮非常量表達式的可能值。換句話說,出于控制流分析的目的,給定類型的非常量表達式被認為具有該類型的任何可能值。

在這個例子中

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

if語句的布爾表達式是一個常量表達式,因為運算==符的兩個操作數都是常量。由于常量表達式是在編譯時計算的,因此生成該值時false,Console.WriteLine調用被視為無法訪問。但是,如果i將其更改為局部變量

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

在Console.WriteLine調用被認為是可到達的,即使在現實中,它永遠不會被執行。

功能成員的塊始終被視為可訪問。通過連續評估塊中每個語句的可達性規則,可以確定任何給定語句的可達性。

在這個例子中

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

第二個的可達性Console.WriteLine確定如下:

  • 第一個Console.WriteLine表達式語句是可到達的,因為該F方法的塊是可訪問的。
  • Console.WriteLine可以訪問第一個表達式語句的結束點,因為該語句是可訪問的。
  • 該if語句是可訪問的,因為第一個Console.WriteLine表達式語句的結束點是可到達的。
  • 第二個Console.WriteLine表達式語句是可到達的,因為語句的布爾表達式if沒有常量值false。

在兩種情況下,語句的結束點可以訪問是編譯時錯誤:

  • 因為該switch語句不允許切換部分“通過”到下一個切換部分,所以切換部分的語句列表的結束點可以到達是編譯時錯誤。如果發生此錯誤,通常表示break缺少語句。
  • 它是函數成員塊的結束點的編譯時錯誤,它計算可以訪問的值。如果發生此錯誤,則通常表示return缺少語句。

一個塊允許在一個單一的語句允許上下文中編寫多條語句。

1 block 2 : '{' statement_list? '}' 3 ;

一個塊由一個可選的statement_list(語句列表)組成,括在括號中。如果省略語句列表,則該塊被認為是空的。

一個塊可能包含聲明語句(聲明聲明)。塊中聲明的局部變量或常量的范圍是塊。

塊執行如下:

  • 如果塊為空,則控制轉移到塊的結束點。
  • 如果塊不為空,則將控制轉移到語句列表。當控制到達語句列表的結束點時,控制轉移到塊的結束點。

如果塊本身可訪問,則可以訪問塊的語句列表。

如果塊為空或者可以訪問語句列表的結束點,則可以訪問塊的結束點。

阿塊包含一個或多個yield語句(yield語句)被稱為迭代器塊。迭代器塊用于將函數成員實現為迭代器(迭代器)。迭代器塊有一些額外的限制:

  • return語句出現在迭代器塊中是一個編譯時錯誤(但yield return允許使用語句)。
  • 迭代器塊包含不安全的上下文(Unsafe contexts)是編譯時錯誤。迭代器塊總是定義一個安全上下文,即使它的聲明嵌套在不安全的上下文中也是如此。

語句列表

一個語句列表由順序寫入的一個或多個語句。語句列表出現在塊?s(塊)和switch_blocks(switch語句)中。

1 statement_list 2 : statement+ 3 ;

通過將控制轉移到第一個語句來執行語句列表。當控制到達語句的結束點時,控制權轉移到下一個語句。當控制到達最后一個語句的結束點時,控制權轉移到語句列表的結束點。

如果至少滿足下列條件之一,則可以訪問語句列表中的語句:

  • 該語句是第一個語句,語句列表本身是可訪問的。
  • 可以訪問上一個語句的結束點。
  • 該語句是帶標簽的語句,標簽由可訪問的goto語句引用。

如果列表中最后一個語句的結束點可達,則可以訪問語句列表的結束點。

空語句

一個empty_statement什么都不做。

1 empty_statement 2 : ';' 3 ;

如果在需要語句的上下文中沒有要執行的操作,則使用空語句。

執行空語句只是將控制轉移到語句的結束點。因此,如果可以訪問空語句,則可以訪問空語句的結束點。

使用while?null主體編寫語句時可以使用空語句:

1 bool ProcessMessage() {...} 2 3 void ProcessMessages() { 4 while (ProcessMessage()) 5 ; 6 }

此外,可以使用空語句}在塊的結束“?”?之前聲明標簽:

1 void F() { 2 ... 3 if (done) goto exit; 4 ... 5 exit: ; 6 }

標簽語句

一個labeled_statement允許一個標簽作為前綴的聲明。塊中允許使用帶標簽的語句,但不允許使用嵌入語句。

1 labeled_statement 2 : identifier ':' statement 3 ;

帶標簽的語句聲明一個標簽,其名稱由標識符指定。標簽的范圍是聲明標簽的整個塊,包括任何嵌套塊。具有相同名稱的兩個標簽具有重疊范圍是編譯時錯誤。

可以從標簽范圍內的goto語句(goto語句)引用標簽。這意味著goto語句可以在塊內和塊之外傳輸控制,但永遠不會轉移到塊中。

標簽有自己的聲明空間,不會干擾其他標識符。這個例子

1 int F(int x) { 2 if (x >= 0) goto x; 3 x = -x; 4 x: return x; 5 }

是有效的,并將名稱x用作參數和標簽。

標簽語句的執行完全對應于標簽后面的語句的執行。

除了正常控制流提供的可訪問性之外,如果標簽由可訪問goto語句引用,則可以訪問帶標簽的語句。(例外:如果goto語句位于try包含finally塊的內部,并且帶標簽的語句在該區域之外try,并且該finally塊的結束點無法訪問,則無法從該goto語句訪問帶標簽的語句。)

聲明語句

一個declaration_statement聲明一個局部變量或常量。聲明語句在塊中是允許的,但不允許作為嵌入語句。

1 declaration_statement 2 : local_variable_declaration ';' 3 | local_constant_declaration ';' 4 ;

局部變量聲明

一個local_variable_declaration聲明一個或多個局部變量。

1 local_variable_declaration 2 : local_variable_type local_variable_declarators 3 ; 4 5 local_variable_type 6 : type 7 | 'var' 8 ; 9 10 local_variable_declarators 11 : local_variable_declarator 12 | local_variable_declarators ',' local_variable_declarator 13 ; 14 15 local_variable_declarator 16 : identifier 17 | identifier '=' local_variable_initializer 18 ; 19 20 local_variable_initializer 21 : expression 22 | array_initializer 23 | local_variable_initializer_unsafe 24 ;

所述local_variable_type一個的local_variable_declaration直接指定由該聲明引入的變量的類型,或與該標識符指示var該類型應該根據一個初始化來推斷。該類型后跟一個local_variable_declarator列表,每個都引入一個新變量。甲local_variable_declarator由一個的標識符名稱變量,任選地隨后通過“?=”令牌和local_variable_initializer,使該變量的初始值。

在局部變量聲明的上下文中,標識符var充當上下文關鍵字(關鍵字)。當local_variable_type被指定為var并且沒有命名的類型var在范圍內時,聲明是隱式類型的局部變量聲明,其類型是從關聯的初始化表達式的類型。隱式類型的局部變量聲明受以下限制:

  • 該local_variable_declaration不能包含多個local_variable_declarator秒。
  • 該local_variable_declarator必須包括local_variable_initializer。
  • 所述local_variable_initializer必須是表達。
  • 初始化表達式必須具有編譯時類型。
  • 初始化表達式不能引用聲明的變量本身

以下是不正確的隱式類型局部變量聲明的示例:

1 var x; // Error, no initializer to infer type from 2 var y = {1, 2, 3}; // Error, array initializer not permitted 3 var z = null; // Error, null does not have a type 4 var u = x => x + 1; // Error, anonymous functions do not have a type 5 var v = v++; // Error, initializer cannot refer to variable itself

使用simple_name(簡單名稱)在表達式中獲取局部變量的值,并使用賦值(賦值運算符)修改局部變量的值。必須在獲得其值的每個位置明確賦值(定義賦值)局部變量。

在local_variable_declaration中聲明的局部變量的范圍是聲明發生的塊。在局部變量的local_variable_declarator之前的文本位置引用局部變量是錯誤的。在局部變量的范圍內,聲明另一個具有相同名稱的局部變量或常量是編譯時錯誤。

聲明多個變量的局部變量聲明等效于具有相同類型的單個變量的多個聲明。此外,局部變量聲明中的變量初始值設定項與聲明后立即插入的賦值語句完全對應。

這個例子

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

完全對應于

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

在隱式類型的局部變量聲明中,聲明的局部變量的類型與用于初始化變量的表達式的類型相同。例如:

1 var i = 5; 2 var s = "Hello"; 3 var d = 1.0; 4 var numbers = new int[] {1, 2, 3}; 5 var orders = new Dictionary<int,Order>();

上面隱式類型化的局部變量聲明與以下顯式類型聲明完全等效:

1 int i = 5; 2 string s = "Hello"; 3 double d = 1.0; 4 int[] numbers = new int[] {1, 2, 3}; 5 Dictionary<int,Order> orders = new Dictionary<int,Order>();

局部常量聲明

一個local_constant_declaration聲明一個或多個局部常量。

1 local_constant_declaration 2 : 'const' type constant_declarators 3 ; 4 5 constant_declarators 6 : constant_declarator (',' constant_declarator)* 7 ; 8 9 constant_declarator 10 : identifier '=' constant_expression 11 ;

該類型一的local_constant_declaration指定由該聲明引入的常數的類型。該類型后面是一個constant_declarator列表,每個都引入一個新的常量。甲constant_declarator由一個的標識符名稱的恒定,接著是“?=”標記,接著是constant_expression(常量表達式給出的常數的值)。

本地常量聲明的類型和constant_expression必須遵循與常量成員聲明(常量)相同的規則。

使用simple_name(簡單名稱)在表達式中獲取局部常量的值。

局部常量的范圍是聲明發生的塊。在constant_declarator之前的文本位置引用局部常量是錯誤的。在局部常量的范圍內,聲明另一個具有相同名稱的局部變量或常量是編譯時錯誤。

聲明多個常量的局部常量聲明等效于具有相同類型的單個常量的多個聲明。

表達式語句

一個expression_statement計算所給定的表達。表達式計算的值(如果有)將被丟棄。

1 expression_statement 2 : statement_expression ';' 3 ; 4 5 statement_expression 6 : invocation_expression 7 | null_conditional_invocation_expression 8 | object_creation_expression 9 | assignment 10 | post_increment_expression 11 | post_decrement_expression 12 | pre_increment_expression 13 | pre_decrement_expression 14 | await_expression 15 ;

并非所有表達式都被允許作為語句。特別是,諸如x + y和x == 1僅僅計算一個值(將被丟棄)的表達式不允許作為語句。

執行expression_statement會計算包含的表達式,然后將控制權轉移到expression_statement的結束點。如果可以訪問expression_statement,則可以訪問expression_statement的結束點。

Selection語句

Selection語句根據某個表達式的值選擇一些可能的語句來執行。

1 selection_statement 2 : if_statement 3 | switch_statement 4 ;

if語句

該if語句根據布爾表達式的值選擇要執行的語句。

1 if_statement 2 : 'if' '(' boolean_expression ')' embedded_statement 3 | 'if' '(' boolean_expression ')' embedded_statement 'else' embedded_statement 4 ;

一個else部分與詞法最近的前一個相關聯的if由該句法允許的。因此,if形式的陳述

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

相當于

1 if (x) { 2 if (y) { 3 F(); 4 } 5 else { 6 G(); 7 } 8 }

一個if語句的執行方式如下:

  • 所述邏輯表達式(布爾表達式)進行評價。
  • 如果布爾表達式產生true,則控制轉移到第一個嵌入語句。當控制到達該語句的結束點時,控制權轉移到if語句的結束點。
  • 如果布爾表達式產生false并且如果存在else部件,則控制轉移到第二個嵌入語句。當控制到達該語句的結束點時,控制權轉移到if語句的結束點。
  • 如果布爾表達式產生false并且如果else部件不存在,則控制轉移到if語句的結束點。

if如果if語句可達且布爾表達式沒有常量值,則可以訪問語句的第一個嵌入語句false。

if如果if語句可訪問且布爾表達式不具有常量值,則語句的第二個嵌入語句(如果存在)是可到達的true。

一個的結束點if語句是可到達如果嵌入語句中至少一個的結束點是可到達。此外,如果語句可以訪問且布爾表達式沒有常量值,則可以訪問if沒有任何else部分的語句的結束點。iftrue

switch語句

switch語句選擇執行一個語句列表,該列表具有與switch表達式的值相對應的關聯開關標簽。

1 switch_statement 2 : 'switch' '(' expression ')' switch_block 3 ; 4 5 switch_block 6 : '{' switch_section* '}' 7 ; 8 9 switch_section 10 : switch_label+ statement_list 11 ; 12 13 switch_label 14 : 'case' constant_expression ':' 15 | 'default' ':' 16 ;

在switch_statement由關鍵字switch,隨后是括號表達式(稱為開關表達),接著是switch_block。所述switch_block由零個或多個switch_section?S,在大括號。每個switch_section包含一個或多個switch_label,后跟一個statement_list(語句列表)。

該管理型?A的switch陳述,由開關式成立。

  • 如果開關表達式的類型是sbyte,byte,short,ushort,int,uint,long,ulong,bool,char,string,或enum_type,或者如果它是對應于這些類型之一的空類型,那么這就是的主導類型switch的語句。
  • 否則,只有一個用戶定義的隱式轉換(用戶定義的轉換)必須從開關表達式的類型存在以下可能的主導類型之一:sbyte,byte,short,ushort,int,uint,long,ulong,char,string,或,對應于空類型其中一種類型。
  • 否則,如果不存在此類隱式轉換,或者如果存在多個此類隱式轉換,則會發生編譯時錯誤。

每個case標簽的常量表達式必須表示一個可隱式轉換的值(隱式轉換)到該switch語句的控制類型。如果case同一switch語句中的兩個或多個標簽指定相同的常量值,則會發生編譯時錯誤。

defaultswitch語句中最多只能有一個標簽。

一個switch語句的執行過程如下:

  • 評估switch表達式并將其轉換為管理類型。
  • 如果case同一switch語句中的標簽中指定的常量之一等于switch表達式的值,則控制將轉移到匹配case標簽后面的語句列表中。
  • 如果case同一switch語句中的標簽中指定的常量都不等于switch表達式的值,并且如果存在default標簽,則控制將轉移到default標簽后面的語句列表中。
  • 如果case同一switch語句中的標簽中指定的常量都不等于switch表達式的值,并且如果不存在default標簽,則控制將轉移到switch語句的結束點。

如果可以訪問switch部分的語句列表的結束點,則會發生編譯時錯誤。這被稱為“不通過”規則。這個例子

1 switch (i) { 2 case 0: 3 CaseZero(); 4 break; 5 case 1: 6 CaseOne(); 7 break; 8 default: 9 CaseOthers(); 10 break; 11 }

是有效的,因為沒有切換部分具有可到達的終點。與C和C ++不同,開關部分的執行不允許“通過”到下一個開關部分和示例

1 switch (i) { 2 case 0: 3 CaseZero(); 4 case 1: 5 CaseZeroOrOne(); 6 default: 7 CaseAny(); 8 }

導致編譯時錯誤。當執行交換機部分后執行另一個交換機部分時,必須使用顯式goto case或goto default語句:

1 switch (i) { 2 case 0: 3 CaseZero(); 4 goto case 1; 5 case 1: 6 CaseZeroOrOne(); 7 goto default; 8 default: 9 CaseAny(); 10 break; 11 }

switch_section中允許使用多個標簽。這個例子

1 switch (i) { 2 case 0: 3 CaseZero(); 4 break; 5 case 1: 6 CaseOne(); 7 break; 8 case 2: 9 default: 10 CaseTwo(); 11 break; 12 }

已驗證。該示例不“通過不落”的規則違反,因為標簽case 2:和default:是相同的部分switch_section。

“no fall through”規則可以防止在break語句被意外省略時出現在C和C ++中的常見錯誤類。此外,由于此規則,switch語句的切換部分可以任意重新排列,而不會影響語句的行為。例如,switch可以顛倒上述語句的各個部分,而不會影響語句的行為:

1 switch (i) { 2 default: 3 CaseAny(); 4 break; 5 case 1: 6 CaseZeroOrOne(); 7 goto default; 8 case 0: 9 CaseZero(); 10 goto case 1; 11 }

switch部分的語句列表通常以a?break,goto case或goto default語句結尾,但允許呈現語句列表的端點不可達的任何構造。例如,已知while由布爾表達式控制的語句true永遠不會到達其終點。同樣,throw或者return語句總是將控制轉移到其他地方并且永遠不會到達其終點。因此,以下示例有效:

1 switch (i) { 2 case 0: 3 while (true) F(); 4 case 1: 5 throw new ArgumentException(); 6 case 2: 7 return; 8 }

switch聲明的管理類型可以是類型string。例如:

1 void DoCommand(string command) { 2 switch (command.ToLower()) { 3 case "run": 4 DoRun(); 5 break; 6 case "save": 7 DoSave(); 8 break; 9 case "quit": 10 DoQuit(); 11 break; 12 default: 13 InvalidCommand(command); 14 break; 15 } 16 }

與字符串相等運算符(字符串相等運算符)一樣,該switch語句區分大小寫,并且僅當開關表達式字符串與case標簽常量完全匹配時才會執行給定的開關部分。

當switch語句的控制類型為時string,該值null被允許作為案例標簽常量。

該STATEMENT_LIST一個第switch_block可以包含聲明語句(聲明語句)。在switch塊中聲明的局部變量或常量的范圍是switch塊。

如果switch語句可訪問且至少滿足下列條件之一,則可以訪問給定switch部分的語句列表:

  • switch表達式是一個非常量值。
  • switch表達式是一個與caseswitch部分中的標簽匹配的常量值。
  • switch表達式是一個與任何case標簽都不匹配的常量值,switch部分包含default標簽。
  • 交換機部分的交換機標簽由可達goto case或goto default語句引用。

switch如果至少滿足下列條件之一,則可以訪問語句的結束點:

  • 該switch語句包含break退出switch語句的可訪問語句。
  • 該switch語句是可到達的,switch表達式是不恒定的值,并且沒有default標簽存在。
  • 該switch語句是可訪問的,switch表達式是一個與任何case標簽都不匹配的常量值,并且不存在default標簽。

迭代語句

迭代語句重復執行嵌入語句。

1 iteration_statement 2 : while_statement 3 | do_statement 4 | for_statement 5 | foreach_statement 6 ;

while語句

該while語句有條件地執行嵌入語句零次或多次。

1 while_statement 2 : 'while' '(' boolean_expression ')' embedded_statement 3 ;

一個while語句的執行過程如下:

  • 所述邏輯表達式(布爾表達式)進行評價。
  • 如果布爾表達式產生true,則控制轉移到嵌入語句。當控制到達嵌入語句的結束點時(可能來自continue語句的執行),控制轉移到while語句的開頭。
  • 如果布爾表達式產生false,則控制轉移到while語句的結束點。

在語句的嵌入語句中while,break語句(break語句)可用于將控制轉移到while語句的結束點(從而結束嵌入語句的迭代),并且continue語句(continue語句)可用于將控制轉移到嵌入語句的結束點(從而執行語句的另一次迭代while)。

while如果while語句可訪問且布爾表達式沒有常量值,則可以訪問語句的嵌入語句false。

while如果至少滿足下列條件之一,則可以訪問語句的結束點:

  • 該while語句包含break退出while語句的可訪問語句。
  • 該while語句是可訪問的,并且布爾表達式沒有常量值true。

do語句

該do語句有條件地執行嵌入語句一次或多次。

1 do_statement 2 : 'do' embedded_statement 'while' '(' boolean_expression ')' ';' 3 ;

一個do語句的執行過程如下:

  • 控制轉移到嵌入語句。
  • 當控件到達嵌入語句的結束點時(可能來自continue語句的執行),將評估boolean_expression(布爾表達式)。如果布爾表達式產生true,則控制轉移到do語句的開頭。否則,控制轉移到do語句的結束點。

在語句的嵌入語句中do,break語句(break語句)可用于將控制轉移到do語句的結束點(從而結束嵌入語句的迭代),并且continue語句(continue語句)可用于將控制轉移到嵌入語句的結束點。

do如果do語句可訪問,則可以訪問語句的嵌入語句。

do如果至少滿足下列條件之一,則可以訪問語句的結束點:

  • 該do語句包含break退出do語句的可訪問語句。
  • 嵌入語句的結束點是可到達的,布爾表達式沒有常量值true。

for語句

該for語句評估一系列初始化表達式,然后在條件為真時重復執行嵌入語句并計算迭代表達式序列。

1 for_statement 2 : 'for' '(' for_initializer? ';' for_condition? ';' for_iterator? ')' embedded_statement 3 ; 4 5 for_initializer 6 : local_variable_declaration 7 | statement_expression_list 8 ; 9 10 for_condition 11 : boolean_expression 12 ; 13 14 for_iterator 15 : statement_expression_list 16 ; 17 18 statement_expression_list 19 : statement_expression (',' statement_expression)* 20 ;

for_initializer,如果存在的話,由一個或者的local_variable_declaration(本地變量聲明)或列表statement_expression?S(表達式語句由逗號分隔)。由for_initializer聲明的局部變量的范圍從變量的local_variable_declarator開始,并延伸到嵌入語句的末尾。范圍包括for_condition和for_iterator。

的for_condition,如果存在的話,必須是一個邏輯表達式(布爾表達式)。

的for_iterator,如果存在,包含的列表的statement_expression?S(表達式語句由逗號分隔)。

for語句執行如下:

  • 如果存在for_initializer,則變量初始值設定項或語句表達式按其寫入順序執行。此步驟僅執行一次。
  • 如果存在for_condition,則對其進行評估。
  • 如果for_condition不存在或者評估結果true,則控制權轉移到嵌入語句。當控件到達嵌入語句的結束點時(可能來自語句的執行continue),for_iterator的表達式(如果有的話)按順序計算,然后執行另一次迭代,從評估for_condition開始。上面的步驟。
  • 如果存在for_condition并且評估結果false,則控制轉移到for語句的結束點。

在語句的嵌入語句中for,break語句(break語句)可用于將控制轉移到for語句的結束點(從而結束嵌入語句的迭代),并且continue語句(continue語句)可用于將控制轉移到嵌入語句的結束點(從而執行for_iterator并執行for語句的另一次迭代,從for_condition開始)。

for如果滿足下列條件之一,則可以訪問語句的嵌入語句:

  • 該for語句是可訪問的,并且不存在for_condition。
  • 該for語句是可訪問的,并且存在for_condition并且沒有常量值false。

for如果至少滿足下列條件之一,則可以訪問語句的結束點:

  • 該for語句包含break退出for語句的可訪問語句。
  • 該for語句是可訪問的,并且存在for_condition并且沒有常量值true。

foreach語句

該foreach語句枚舉集合的元素,為集合的每個元素執行嵌入式語句。

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

的類型和標識符一個的foreach聲明聲明迭代變量的聲明。如果var標識符作為local_variable_type給出,并且沒有命名的類型var在范圍內,則迭代變量被稱為隱式類型的迭代變量,并且其類型被視為foreach語句的元素類型,如下所述。迭代變量對應于只讀局部變量,其范圍擴展到嵌入語句。執行期間foreach聲明,迭代變量表示當前正在執行迭代的集合元素。如果嵌入語句試圖修改迭代變量(通過賦值或發生編譯時間錯誤++和--操作員)或通過迭代變量作為ref或out參數。

在下文中,為了簡潔,IEnumerable,IEnumerator,IEnumerable<T>和IEnumerator<T>指的是命名空間的相應類型System.Collections和System.Collections.Generic。

foreach語句的編譯時處理首先確定表達式的集合類型,枚舉器類型和元素類型。該決定如下:

  • 如果類型X的表達是一個數組類型,那么存在來自隱式引用轉換X到IEnumerable接口(因為System.Array實現該接口)。的集合類型是IEnumerable接口,該枚舉類型是IEnumerator接口和元素類型是陣列類型的元素類型X。
  • 如果類型X的表達是dynamic則存在從隱式轉換表達式的IEnumerable接口(隱式動態轉換)。該集合類型是IEnumerable接口和枚舉類型是IEnumerator接口。如果var標識符是local_variable_type,那么元素類型是dynamic,否則它是object。
  • 否則,確定類型X是否具有適當的GetEnumerator方法:

    • 對X具有標識符GetEnumerator且沒有類型參數的類型執行成員查找。如果成員查找不產生匹配,或者產生歧義,或產生不是方法組的匹配,請檢查可枚舉接口,如下所述。如果成員查找產生除方法組或不匹配之外的任何內容,建議發出警告。
    • 使用生成的方法組和空參數列表執行重載解析。如果重載決策導致沒有適用的方法,導致歧義,或導致單個最佳方法但該方法是靜態的或不公開的,請檢查可枚舉的接口,如下所述。如果重載決策產生除明確的公共實例方法或沒有適用的方法之外的任何內容,建議發出警告。
    • 如果返回類型E的的GetEnumerator方法不是類,結構或接口類型,則產生一個錯誤,并且不采取進一步的步驟。
    • E使用標識符執行成員查找Current,不使用類型參數。如果成員查找不產生匹配,則結果是錯誤,或者結果是除允許讀取的公共實例屬性之外的任何內容,產生錯誤并且不執行進一步的步驟。
    • E使用標識符執行成員查找MoveNext,不使用類型參數。如果成員查找不產生匹配,則結果是錯誤,或者結果是除方法組之外的任何內容,產生錯誤并且不執行進一步的步驟。
    • 使用空參數列表對方法組執行重載分辨率。如果重載決策導致沒有適用的方法,導致歧義,或導致單個最佳方法但該方法是靜態的或不公開的,或者其返回類型不是bool,則產生錯誤并且不采取進一步的步驟。
    • 的集合類型是X,該枚舉類型是E,和元素類型是類型Current屬性。
  • 否則,檢查可枚舉的接口:

    • 如果所有的類型中Ti對于其存在從隱式轉換X到IEnumerable<Ti>,有一種獨特類型T,使得T不dynamic和所有其他Ti有從隱式轉換IEnumerable<T>到IEnumerable<Ti>,則該集合類型是接口IEnumerable<T>,該枚舉類型是接口IEnumerator<T>,元素類型是T。
    • 否則,如果存在多個這樣的類型T,則產生錯誤并且不采取進一步的步驟。
    • 否則,如果存在的隱式轉換從X到System.Collections.IEnumerable接口,則集合類型是這樣的接口,所述枚舉類型是接口System.Collections.IEnumerator,并且元素類型是object。
    • 否則,將產生錯誤,并且不會采取進一步的步驟。

上述步驟如果成功,則明確地生成集合類型C,枚舉器類型E和元素類型T。表格的foreach聲明

foreach (V v in x) embedded_statement

然后擴展到:

1 { 2 E e = ((C)(x)).GetEnumerator(); 3 try { 4 while (e.MoveNext()) { 5 V v = (V)(T)e.Current; 6 embedded_statement 7 } 8 } 9 finally { 10 ... // Dispose e 11 } 12 }

變量e對表達式x或嵌入語句或程序的任何其他源代碼不可見或不可訪問。該變量v在嵌入語句中是只讀的。如果沒有從(元素類型)到(foreach語句中的local_variable_type)的顯式轉換(顯式轉換),則會產生錯誤,并且不會采取進一步的步驟。如果有值,則在運行時拋出a?。TVxnullSystem.NullReferenceException

允許實現以不同方式實現給定的foreach語句,例如出于性能原因,只要行為與上述擴展一致即可。

vwhile循環內部的位置對于embedded_statement中發生的任何匿名函數如何捕獲它非常重要。

例如:

1 int[] values = { 7, 9, 13 }; 2 Action f = null; 3 4 foreach (var value in values) 5 { 6 if (f == null) f = () => Console.WriteLine("First value: " + value); 7 } 8 9 f();

如果v在while循環之外聲明,它將在所有迭代之間共享,并且它在for循環之后的值將是最終值13,這f將是打印的調用。相反,因為每次迭代都有自己的變量v,f在第一次迭代中捕獲的變量將繼續保持值7,即將打印的值。(注意:早期版本的C#v在while循環之外聲明。)

finally塊的主體按照以下步驟構造:

  • 如果存在從一個隱式轉換E到System.IDisposable接口,則

    • 如果E是非可空值類型,則finally子句將擴展為語義等效于:

    • 1 finally { 2 ((System.IDisposable)e).Dispose(); 3 }
    • ?否則,finally子句將擴展為語義等效于:
    • 1 finally { 2 if (e != null) ((System.IDisposable)e).Dispose(); 3 }

      除了if?E是值類型,或實例化為值類型的類型參數之外,to的強制e轉換System.IDisposable不會導致裝箱發生。

  • 否則,如果E是密封類型,則finally子句將擴展為空塊:

1 finally { 2 }
  • 否則,finally子句擴展為:

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

d任何用戶代碼都看不到或訪問本地變量。特別是,它不會與其范圍包含finally塊的任何其他變量沖突。

foreach遍歷數組元素的順序如下:對于單維數組,元素以遞增的索引順序遍歷,從索引開始,以索引0結束Length - 1。對于多維數組,遍歷元素,使得最右邊的維度的索引首先增加,然后是下一個左維度,依此類推到左邊。

以下示例按元素順序打印出二維數組中的每個值:

1 using System; 2 3 class Test 4 { 5 static void Main() { 6 double[,] values = { 7 {1.2, 2.3, 3.4, 4.5}, 8 {5.6, 6.7, 7.8, 8.9} 9 }; 10 11 foreach (double elementValue in values) 12 Console.Write("{0} ", elementValue); 13 14 Console.WriteLine(); 15 } 16 }

產生的產出如下:

1.2 2.3 3.4 4.5 5.6 6.7 7.8 8.9

在這個例子中

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

n推斷的類型是int,元素類型numbers。

跳轉語句

跳轉語句無條件地轉移控制。

1 jump_statement 2 : break_statement 3 | continue_statement 4 | goto_statement 5 | return_statement 6 | throw_statement 7 ;

跳轉語句轉移控制的位置稱為跳轉語句的目標。

當一個塊內發生跳轉語句,并且該跳轉語句的目標位于該塊之外時,跳轉語句被稱為退出該塊。雖然跳轉語句可以將控制轉移出塊,但它永遠不會將控制轉移到塊中。

由于存在干預try語句,跳轉語句的執行變得復雜。在沒有這樣的try語句的情況下,跳轉語句無條件地將控制從跳轉語句轉移到其目標。在存在這樣的干預try陳述的情況下,執行更加復雜。如果跳轉語句退出try具有關聯finally塊的一個或多個塊,則控制最初被轉移到finally最內層try語句的塊。當控制到達finally塊的結束點時,控制轉移到finally下一個封閉try語句的塊。重復該過程,直到執行finally了所有干預try語句的塊。

在這個例子中

1 using System; 2 3 class Test 4 { 5 static void Main() { 6 while (true) { 7 try { 8 try { 9 Console.WriteLine("Before break"); 10 break; 11 } 12 finally { 13 Console.WriteLine("Innermost finally block"); 14 } 15 } 16 finally { 17 Console.WriteLine("Outermost finally block"); 18 } 19 } 20 Console.WriteLine("After break"); 21 } 22 }

在將控制轉移到跳轉語句的目標之前,執行finally與兩個try語句關聯的塊。

產生的產出如下:

1 Before break 2 Innermost finally block 3 Outermost finally block 4 After break

break語句

該break語句退出直接封閉switch,while,do,for,或foreach語句。

1 break_statement 2 : 'break' ';' 3 ;

一個目標break的語句是最近的封閉的結束點switch,while,do,for,或foreach語句。如果break語句不是由一個封閉的switch,while,do,for,或foreach語句,將發生編譯時錯誤。

當多個switch,while,do,for,或foreach語句相互嵌套,一個break聲明僅適用于最里面的語句。要跨多個嵌套級別傳輸控制,必須使用goto語句(goto語句)。

一個break語句不能退出一個finally塊(try語句)。當一個break語句出現在一個finally塊中時,該break語句的目標必須在同一個finally塊內;?否則,發生編譯時錯誤。

一個break語句的執行過程如下:

  • 如果break語句退出try具有關聯finally塊的一個或多個塊,則控制最初被轉移到finally最內層try語句的塊。當控制到達finally塊的結束點時,控制轉移到finally下一個封閉try語句的塊。重復該過程,直到執行finally了所有干預try語句的塊。
  • 控制權轉移到break聲明的目標。

因為break語句無條件地將控制權轉移到其他地方,所以break語句的終點永遠不可達。

continue語句

該continue語句開始直接封閉的一個新的迭代while,do,for,或foreach語句。

1 continue_statement 2 : 'continue' ';' 3 ;

一個目標continue的語句是最近的封閉的嵌入語句的結束點while,do,for,或foreach語句。如果continue語句不是由一個封閉的while,do,for,或foreach語句,將發生編譯時錯誤。

當多個while,do,for,或foreach語句相互嵌套,一個continue聲明僅適用于最里面的語句。要跨多個嵌套級別傳輸控制,必須使用goto語句(goto語句)。

一個continue語句不能退出一個finally塊(try語句)。當一個continue語句出現在一個finally塊中時,該continue語句的目標必須在同一個finally塊內;?否則會發生編譯時錯誤。

一個continue語句的執行過程如下:

  • 如果continue語句退出try具有關聯finally塊的一個或多個塊,則控制最初被轉移到finally最內層try語句的塊。當控制到達finally塊的結束點時,控制轉移到finally下一個封閉try語句的塊。重復該過程,直到執行finally了所有干預try語句的塊。
  • 控制權轉移到continue聲明的目標。

因為continue語句無條件地將控制權轉移到其他地方,所以continue語句的終點永遠不可達。

goto語句

該goto語句將控制轉移到由標簽標記的語句。

1 goto_statement 2 : 'goto' identifier ';' 3 | 'goto' 'case' constant_expression ';' 4 | 'goto' 'default' ';' 5 ;

goto?標識符語句的目標是帶有給定標簽的帶標簽語句。如果當前函數成員中不存在具有給定名稱的標簽,或者該goto語句不在標簽的范圍內,則會發生編譯時錯誤。此規則允許使用goto語句將控制權移出嵌套作用域,但不能轉移到嵌套作用域中。在這個例子中

1 using System; 2 3 class Test 4 { 5 static void Main(string[] args) { 6 string[,] table = { 7 {"Red", "Blue", "Green"}, 8 {"Monday", "Wednesday", "Friday"} 9 }; 10 11 foreach (string str in args) { 12 int row, colm; 13 for (row = 0; row <= 1; ++row) 14 for (colm = 0; colm <= 2; ++colm) 15 if (str == table[row,colm]) 16 goto done; 17 18 Console.WriteLine("{0} not found", str); 19 continue; 20 done: 21 Console.WriteLine("Found {0} at [{1}][{2}]", str, row, colm); 22 } 23 } 24 }

一個goto語句是用來傳輸控制出嵌套范圍。

goto case語句的目標是直接封閉switch語句(switch語句)中的語句列表,其中包含case具有給定常量值的標簽。如果goto case語句沒有被switch語句包含,如果constant_expression不能隱式轉換(隱式轉換)到最近的封閉switch語句的控制類型,或者如果最近的封閉switch語句不包含case具有給定常量值的標簽,則編譯發生時間錯誤。

goto default語句的目標是直接包含switch語句(switch語句)中的語句列表,其中包含default標簽。如果goto default語句未包含在switch語句中,或者最近的封閉switch語句不包含default標簽,則會發生編譯時錯誤。

一個goto語句不能退出一個finally塊(try語句)。當goto語句在finally塊中發生時,goto語句的目標必須在同一個finally塊內,否則會發生編譯時錯誤。

一個goto語句的執行過程如下:

  • 如果goto語句退出try具有關聯finally塊的一個或多個塊,則控制最初被轉移到finally最內層try語句的塊。當控制到達finally塊的結束點時,控制轉移到finally下一個封閉try語句的塊。重復該過程,直到執行finally了所有干預try語句的塊。
  • 控制權轉移到goto聲明的目標。

因為goto語句無條件地將控制權轉移到其他地方,所以goto語句的終點永遠不可達。

return語句

該return語句將控制權返回給return語句出現的函數的當前調用者。

1 return_statement 2 : 'return' expression? ';' 3 ;

return不帶表達式語句可用于僅在一個功能部件,其不計算的值,即,與結果類型的方法(方法體)void,所述set屬性或索引的訪問,所述add與remove事件的存取器,一個實例構造函數,靜態構造函數或析構函數。

return具有表達式的語句只能在計算值的函數成員中使用,即具有非void結果類型的方法,get屬性或索引器的訪問者或用戶定義的運算符。隱式轉換(隱式轉換)必須存在,從表達式的類型到包含函數成員的返回類型。

返回語句也可以在匿名函數表達式(匿名函數表達式)的主體中使用,并參與確定這些函數存在哪些轉換。

return語句出現在finally塊(try語句)中是編譯時錯誤。

一個return語句的執行過程如下:

  • 如果return語句指定了表達式,則計算表達式,并通過隱式轉換將結果值轉換為包含函數的返回類型。轉換的結果成為函數產生的結果值。
  • 如果return語句被一個或多個try或catch帶有關聯finally塊的塊包圍,則控制最初被轉移到finally最內層try語句的塊。當控制到達finally塊的結束點時,控制轉移到finally下一個封閉try語句的塊。重復此過程,直到執行finally了所有封閉try語句的塊。
  • 如果包含函數不是異步函數,則控制將返回包含函數的調用者以及結果值(如果有)。
  • 如果包含函數是異步函數,則控制將返回到當前調用者,并且結果值(如果有)將記錄在返回任務中,如(枚舉器接口)中所述。

因為return語句無條件地將控制權轉移到其他地方,所以return語句的終點永遠不可達。

throw語句

該throw語句拋出異常。

1 throw_statement 2 : 'throw' expression? ';' 3 ;

throw帶有表達式的語句會拋出通過計算表達式生成的值。表達式必須表示類類型的值,該類類型System.Exception的類類型派生自System.Exception或具有System.Exception(或其子類)作為其有效基類的類型參數類型。如果表達式的評估產生null,System.NullReferenceException則拋出a?。

throw沒有表達式的語句只能在catch塊中使用,在這種情況下,該語句會重新拋出該catch塊當前正在處理的異常。

因為throw語句無條件地將控制權轉移到其他地方,所以throw語句的終點永遠不可達。

拋出異常時,控制權轉移到可以處理異常catch的封閉try語句中的第一個子句。從拋出異常點到將控制轉移到合適的異常處理程序的過程發生的過程稱為異常傳播。異常的傳播包括重復評估以下步驟,直到catch找到與異常匹配的子句。在本說明書中,拋出點最初是拋出異常的位置。

  • 在當前函數成員中,try將檢查包含拋出點的每個語句。對于每個語句S,從最內層try語句開始到以最外層try語句結束,將評估以下步驟:

    • 如果try塊S包含拋出點并且如果S有一個或多個catch子句,則catch根據出現的順序檢查子句,以根據try語句一節中指定的規則找到異常的合適處理程序。如果找到匹配catch子句,則通過將控制轉移到該catch子句的塊來完成異常傳播。

    • 否則,如果try塊或catch塊S包圍拋出點并且如果S有finally塊,則控制轉移到finally塊。如果finally塊拋出另一個異常,則終止當前異常的處理。否則,當控制到達finally塊的結束點時,繼續處理當前異常。

  • 如果當前函數調用中未找到異常處理程序,則終止函數調用,并發生以下任一情況:

    • 如果當前函數是非異步的,則對函數的調用者重復上述步驟,其拋出點對應于調用函數成員的語句。

    • 如果當前函數是異步和任務返回,則異常將記錄在返回任務中,該任務將進入故障或取消狀態,如枚舉器接口中所述。

    • 如果當前函數是async和void-returns,則會按照Enumerable接口中的描述通知當前線程的同步上下文。

  • 如果異常處理終止當前線程中的所有函數成員調用,指示該線程沒有該異常的處理程序,則該線程本身終止。這種終止的影響是實現定義的。

try語句

該try語句提供了一種機制,用于捕獲在執行塊期間發生的異常。此外,該try語句還提供了指定在控制離開try語句時始終執行的代碼塊的功能。

1 try_statement 2 : 'try' block catch_clause+ 3 | 'try' block finally_clause 4 | 'try' block catch_clause+ finally_clause 5 ; 6 7 catch_clause 8 : 'catch' exception_specifier? exception_filter? block 9 ; 10 11 exception_specifier 12 : '(' type identifier? ')' 13 ; 14 15 exception_filter 16 : 'when' '(' expression ')' 17 ; 18 19 finally_clause 20 : 'finally' block 21 ;

有三種可能的try陳述形式:

  • 一個try塊后跟一個或多個catch塊。
  • 一個try塊然后是一個finally塊。
  • 一個try塊后跟一個或多個catch塊,后跟一個finally塊。

當catch子句指定exception_specifier時,類型必須是System.Exception,派生自System.Exception的類型System.Exception或具有(或其子類)作為其有效基類的類型參數類型。

當catch子句指定兩者exception_specifier與標識符,一個異常變量給定名稱和類型的聲明。異常變量對應于局部變量,其范圍擴展到catch子句。在執行exception_filter和block期間,異常變量表示當前正在處理的異常。出于明確賦值檢查的目的,異常變量在其整個范圍內被認為是明確賦值的。

除非catch子句包含異常變量名稱,否則無法訪問過濾器和catch塊中的異常對象。

一個catch不指定條款exception_specifier被稱為一般catch條款。

一些編程語言可能支持不能表示為從中派生的對象的System.Exception異常,盡管這些異常永遠不會由C#代碼生成。一般catch條款可用于捕獲此類例外。因此,一般catch子句在語義上與指定類型的子句不同System.Exception,因為前者也可以捕獲來自其他語言的異常。

為了找到異常的處理程序,catch以詞法順序檢查子句。如果catch子句指定了類型但沒有異常過濾器,則catch同一try語句中的后一個子句的編譯時錯誤是指定與該類型相同或派生的類型。如果catch子句指定沒有類型且沒有指定過濾器,則它必須是該語句的最后一個catch子句try。

在catch塊中,沒有表達式的throw語句(throw語句)可用于重新拋出catch塊捕獲的異常。對異常變量的賦值不會改變重新拋出的異常。

在這個例子中

1 using System; 2 3 class Test 4 { 5 static void F() { 6 try { 7 G(); 8 } 9 catch (Exception e) { 10 Console.WriteLine("Exception in F: " + e.Message); 11 e = new Exception("F"); 12 throw; // re-throw 13 } 14 } 15 16 static void G() { 17 throw new Exception("G"); 18 } 19 20 static void Main() { 21 try { 22 F(); 23 } 24 catch (Exception e) { 25 Console.WriteLine("Exception in Main: " + e.Message); 26 } 27 } 28 }

該方法F捕獲異常,將一些診斷信息寫入控制臺,更改異常變量,并重新拋出異常。重新拋出的異常是原始異常,因此產生的輸出是:

1 Exception in F: G 2 Exception in Main: G

這是一個編譯時錯誤break,continue或者goto語句將控制轉移出的finally塊。當a?break,continue或goto語句出現在finally塊中時,語句的目標必須位于同一個finally塊中,否則會發生編譯時錯誤。

return在finally塊中發生語句是編譯時錯誤。

一個try語句的執行過程如下:

  • 控制轉移到try塊。
  • 當控件到達try塊的結束點時:

    • 如果try語句有finally塊,finally則執行該塊。
    • 控制權轉移到try聲明的終點。
  • 如果try在執行try塊期間將異常傳播到語句:

    • 這些catch子句(如果有的話)按照外觀的順序進行檢查,以便為異常找到合適的處理程序。如果catch子句未指定類型,或指定異常類型或異常類型的基類型:
      • 如果catch子句聲明了異常變量,則將異常對象分配給異常變量。
      • 如果catch子句聲明了異常過濾器,則會評估過濾器。如果計算結果為false,則catch子句不匹配,并且搜索將繼續通過catch適當處理程序的任何后續子句。
      • 否則,該catch子句被視為匹配,并且控制被轉移到匹配catch塊。
      • 當控件到達catch塊的結束點時:
        • 如果try語句有finally塊,finally則執行該塊。
        • 控制權轉移到try聲明的終點。
      • 如果try在執行catch塊期間將異常傳播到語句:
        • 如果try語句有finally塊,finally則執行該塊。
        • 該異常將傳播到下一個封閉try語句。
    • 如果try語句沒有catch子句或沒有catch子句匹配異常:
      • 如果try語句有finally塊,finally則執行該塊。
      • 該異常將傳播到下一個封閉try語句。

一的語句finally在控制離開塊總是被執行try的語句。這是真實的,控制傳送是否發生正常的執行結果,作為執行的結果break,continue,goto,或return語句,或作為關于傳播異常出的結果try說明。

如果在執行finally塊期間拋出異常,并且未在同一finally塊中捕獲,則異常將傳播到下一個封閉try語句。如果另一個異常處于傳播過程中,則該異常將丟失。傳播異常的過程將在throw語句描述(throw語句)中進一步討論。

在try一個塊try語句是可到達如果try語句是可到達。

一個catch一個的塊try語句是可到達如果try語句是可到達。

在finally一個塊try語句是可到達如果try語句是可到達。

try如果滿足以下兩個條件,則可以訪問語句的結束點:

  • 所述的結束點try塊是可到達的或者至少一個的結束點catch塊是可到達的。
  • 如果finally存在finally塊,則可以訪問塊的結束點。

checked和unchecked語句

checked和unchecked語句用于控制溢出檢查上下文對整型算術運算和轉換。

1 checked_statement 2 : 'checked' block 3 ; 4 5 unchecked_statement 6 : 'unchecked' block 7 ;

checked語句使得塊中的所有表達式都在已檢查的上下文中進行計算,并且該unchecked語句會導致在未檢查的上下文中計算塊中的所有表達式。

該checked和unchecked語句完全等效于checked與unchecked運營商(checked和unchecked經營者,除了他們在塊而不是表達操作)。

lock語句

該lock語句獲取給定對象的互斥鎖,執行語句,然后釋放鎖。

1 lock_statement 2 : 'lock' '(' expression ')' embedded_statement 3 ;

lock語句的表達式必須表示已知為reference_type的類型的值。沒有為語句的表達式執行隱式裝箱轉換(Boxing conversions),因此表達式的lock編譯時錯誤表示value_type的值。

一個lock形式的聲明

lock (x) ...

其中x是reference_type的表達式,恰好相當于

1 bool __lockWasTaken = false; 2 try { 3 System.Threading.Monitor.Enter(x, ref __lockWasTaken); 4 ... 5 } 6 finally { 7 if (__lockWasTaken) System.Threading.Monitor.Exit(x); 8 }

除了x僅評估一次。

在保持互斥鎖定的同時,在同一執行線程中執行的代碼也可以獲取并釋放鎖定。但是,在鎖定釋放之前,阻止在其他線程中執行的代碼獲取鎖定。

System.Type建議不要鎖定對象以同步對靜態數據的訪問。其他代碼可能會鎖定相同的類型,這可能導致死鎖。更好的方法是通過鎖定私有靜態對象來同步對靜態數據的訪問。例如:

1 class Cache 2 { 3 private static readonly object synchronizationObject = new object(); 4 5 public static void Add(object x) { 6 lock (Cache.synchronizationObject) { 7 ... 8 } 9 } 10 11 public static void Remove(object x) { 12 lock (Cache.synchronizationObject) { 13 ... 14 } 15 } 16 }

using語句

該using語句獲取一個或多個資源,執行語句,然后處置該資源。

1 using_statement 2 : 'using' '(' resource_acquisition ')' embedded_statement 3 ; 4 5 resource_acquisition 6 : local_variable_declaration 7 | expression 8 ;

資源是一個類或實現結構System.IDisposable,它包括一個名為單個參數方法Dispose。使用資源的代碼可以調用Dispose以指示不再需要該資源。如果Dispose未調用,則最終會因垃圾收集而自動處理。

如果形式resource_acquisition是local_variable_declaration則類型local_variable_declaration必須是dynamic或可以隱式轉換為類型System.IDisposable。如果resource_acquisition的形式是表達式,那么此表達式必須可以隱式轉換為System.IDisposable。

在resource_acquisition中聲明的局部變量是只讀的,并且必須包含初始化程序。如果嵌入語句試圖修改這些局部變量(通過賦值或發生編譯時間錯誤++和--操作員),把它們的地址,或者將它們傳遞作為ref或out參數。

一個using語句被翻譯成三個部分:獲取,使用和處置。資源的使用隱式包含在try包含finally子句的語句中。該finally子句處理資源。如果null獲取了資源,則不會進行任何調用Dispose,也不會拋出任何異常。如果資源屬于類型dynamic,則在獲取期間通過隱式動態轉換(隱式動態轉換)動態轉換IDisposable,以確保在使用和處置之前轉換成功。

一個using形式的聲明

using (ResourceType resource = expression) statement

對應于三種可能的擴展之一。何時ResourceType是非可空值類型,擴展為

1 { 2 ResourceType resource = expression; 3 try { 4 statement; 5 } 6 finally { 7 ((IDisposable)resource).Dispose(); 8 } 9 }

否則,當ResourceType是可以為空的值類型或除了以外的引用類型時dynamic,擴展為

1 { 2 ResourceType resource = expression; 3 try { 4 statement; 5 } 6 finally { 7 if (resource != null) ((IDisposable)resource).Dispose(); 8 } 9 }

否則,當ResourceType是dynamic,擴展

1 { 2 ResourceType resource = expression; 3 IDisposable d = (IDisposable)resource; 4 try { 5 statement; 6 } 7 finally { 8 if (d != null) d.Dispose(); 9 } 10 }

在任一擴展中,resource變量在嵌入語句中是只讀的,并且d變量在嵌入語句中是不可訪問的,并且對嵌入語句是不可見的。

允許實現以不同方式實現給定的using語句,例如出于性能原因,只要行為與上述擴展一致即可。

一個using形式的聲明

using (expression) statement

有三個可能的擴展。在這種情況下ResourceType隱含的是編譯時類型expression,如果有的話。否則接口IDisposable本身用作ResourceType。該resource變量在嵌入語句中不可訪問且不可訪問。

當resource_acquisition采用local_variable_declaration的形式時,可以獲取給定類型的多個資源。一個using形式的聲明

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

恰好等同于一系列嵌套using語句:

1 using (ResourceType r1 = e1) 2 using (ResourceType r2 = e2) 3 ... 4 using (ResourceType rN = eN) 5 statement

下面的示例創建一個名為的文件,log.txt并將兩行文本寫入該文件。然后,該示例打開相同的文件進行讀取,并將包含的文本行復制到控制臺。

1 using System; 2 using System.IO; 3 4 class Test 5 { 6 static void Main() { 7 using (TextWriter w = File.CreateText("log.txt")) { 8 w.WriteLine("This is line one"); 9 w.WriteLine("This is line two"); 10 } 11 12 using (TextReader r = File.OpenText("log.txt")) { 13 string s; 14 while ((s = r.ReadLine()) != null) { 15 Console.WriteLine(s); 16 } 17 18 } 19 } 20 }

由于TextWriter和TextReader類實現了IDisposable接口,因此該示例可以使用using語句來確保在寫入或讀取操作之后正確關閉基礎文件。

yield語句

yield語句在迭代器塊(Blocks)中使用,以產生迭代器的枚舉器對象(Enumerator對象)或可枚舉對象(Enumerable對象)的值,或表示迭代結束。

1 yield_statement 2 : 'yield' 'return' expression ';' 3 | 'yield' 'break' ';' 4 ;

yield不是保留字;?它有之前用過的,只有當特殊意義return或break關鍵字。在其他情況下,yield可以用作標識符。

yield語句的出現位置有幾個限制,如下所述。

  • yield語句(任一形式)出現在method_body,operator_body或accessor_body之外是編譯時錯誤
  • yield語句(任一形式)出現在匿名函數中是編譯時錯誤。
  • yield語句(任一形式)出現在語句的finally子句中是編譯時錯誤try。
  • yield return語句出現在try包含任何catch子句的語句中的任何位置都是編譯時錯誤。

以下示例顯示了yield語句的一些有效和無效用法。

1 delegate IEnumerable<int> D(); 2 3 IEnumerator<int> GetEnumerator() { 4 try { 5 yield return 1; // Ok 6 yield break; // Ok 7 } 8 finally { 9 yield return 2; // Error, yield in finally 10 yield break; // Error, yield in finally 11 } 12 13 try { 14 yield return 3; // Error, yield return in try...catch 15 yield break; // Ok 16 } 17 catch { 18 yield return 4; // Error, yield return in try...catch 19 yield break; // Ok 20 } 21 22 D d = delegate { 23 yield return 5; // Error, yield in an anonymous function 24 }; 25 } 26 27 int MyMethod() { 28 yield return 1; // Error, wrong return type for an iterator block 29 }

隱式轉換(隱式轉換)必須存在于yield return語句中表達式的類型到迭代器的yield類型(Yield類型)。

一個yield return語句的執行過程如下:

  • 計算語句中給出的表達式,隱式轉換為yield類型,并將其賦值給Current枚舉器對象的屬性。
  • 迭代器塊的執行被暫停。如果yield return語句在一個或多個try塊內,finally則此時不執行關聯的塊。
  • MoveNext枚舉器對象的方法返回true其調用者,指示枚舉器對象成功前進到下一個項目。

對枚舉器對象MoveNext方法的下一次調用將從上次暫停的位置繼續執行迭代器塊。

一個yield break語句的執行過程如下:

  • 如果yield break語句被一個或多個try具有關聯finally塊的塊包圍,則控制最初被轉移到finally最內層try語句的塊。當控制到達finally塊的結束點時,控制轉移到finally下一個封閉try語句的塊。重復此過程,直到執行finally了所有封閉try語句的塊。
  • 控制權返回給迭代器塊的調用者。這是枚舉器對象的MoveNext方法或Dispose方法。

因為yield break語句無條件地將控制權轉移到其他地方,所以yield break語句的終點永遠不可達。

轉載于:https://www.cnblogs.com/strengthen/p/9742587.html

總結

以上是生活随笔為你收集整理的C#6.0语言规范(八) 语句的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。