所有控制流程語句都具有相同的基本特征:根據(jù)一組條件選擇要執(zhí)行的語句。這些語句分三大類,并通過其主要行為進(jìn)行描述。選擇語句和跳轉(zhuǎn)語句最接近,它們選擇的語句都只執(zhí)行一次,而迭代語句重復(fù)執(zhí)行語句。跳轉(zhuǎn)語句無條件地進(jìn)行跳轉(zhuǎn),選擇語句根據(jù)條件選擇要執(zhí)行的語句,而迭代語句根據(jù)條件決定執(zhí)行語句多少次。
一、選擇語句
1.1 if語句
if語句是最基本的選擇語句,它根據(jù)一個(gè)布爾表達(dá)式的結(jié)果選擇執(zhí)行一條語句。
if語句的基本語法如下:
if ( boolean-expression )
embedded-statement
稍微復(fù)雜一點(diǎn)的語法如下:
if(boolean-expression)
consequence-statement
else
alternative-statement
如果boolean-expression的結(jié)果為true,就執(zhí)行consequence-statement;如果boolean-expression的結(jié)果為false,且有else部分,就執(zhí)行alternative-statement。到達(dá)被執(zhí)行的語句末尾后,將執(zhí)行if語句后面的語句。
被執(zhí)行的語句可以是任何有效的語句,包括另一條if語句。在這種情況下,這條if語句稱為嵌套if語句。
ps:else語句不匹配
編寫 if 語句時(shí),一種常見的問題是 else 語句不匹配,即代碼的縮進(jìn)格式與實(shí)際的控制流程不匹配。為幫助避免這種問題,最好使用大括號清楚地指出 else 語句對應(yīng)的 if語句。檢查一系列互斥的條件時(shí),可級聯(lián)if語句,即在else部分使用另一個(gè)if語句。在這種情況下,將按順序檢查條件,直到遇到結(jié)果為true的條件。
1.2 switch語句
可將switch語句視為級聯(lián)if語句的自然進(jìn)化結(jié)果,其功能與級聯(lián)if語句類似,但更簡潔、更靈活。switch語句執(zhí)行與表達(dá)式值相等的標(biāo)簽指定的語句列表。
switch語句的語法如下:
switch ( expression )
{
case constant-expression :
statement-list
break;
default :
statement-list
break;
}
switch語句體稱為switch塊,包含一個(gè)或多個(gè)switch段。每個(gè)switch段至少包含一個(gè)標(biāo)簽,標(biāo)簽后面是一個(gè)語句列表。
expression的類型稱為 switch語句的支配類型(governing type),可以是 sbyte、byte、short、ushort、int、uint、long、ulong、char及其可以為null的版本,還可以為string或枚舉類型。expression只計(jì)算一次。
switch段的標(biāo)簽必須是常量表達(dá)式、在switch塊中是唯一的且可顯式地轉(zhuǎn)換為支配類型。如果switch語句的支配類型為string或可以為null的類型,就可包含case標(biāo)簽null。
ps:支配類型為string的switch語句
expression 的結(jié)果是區(qū)分大小寫,因此僅當(dāng)標(biāo)簽與 expression 完全匹配時(shí),才會(huì)執(zhí)行相應(yīng)的switch段。
如果expression的值與case標(biāo)簽中的常量匹配,就將首先執(zhí)行該標(biāo)簽后面的第一條語句。如果沒有匹配的case標(biāo)簽,且有default標(biāo)簽,就將執(zhí)行該標(biāo)簽后的第一條語句;否則將執(zhí)行switch語句后面的語句。
ps:連續(xù)執(zhí)行
不同于 C 和 C++等編程語言,C# switch 語句不允許連續(xù)執(zhí)行(fall through)switch段,即從一個(gè)switch段執(zhí)行到下一個(gè)switch段。
為禁止連續(xù)執(zhí)行,C#要求所有switch段都以有不可達(dá)終點(diǎn)(unreachable endpoint)的語句結(jié)束。一條這樣的語句是無條件跳轉(zhuǎn)語句,但最常用的是break語句。
通過禁止連續(xù)執(zhí)行,C#消除了C和C++程序中一種常見的錯(cuò)誤,并使得調(diào)整swith段的順序不會(huì)影響switch語句的行為。
ps:作用域
在switch語句中,整個(gè)switch塊是一個(gè)作用域,而每個(gè)switch段不形成作用域。這意味著在 switch 段中聲明變量或常量時(shí),其作用域?yàn)檎麄€(gè)switch塊,而不是當(dāng)前switch段。
如果要將變量或常量的作用域限定為當(dāng)前 switch 段,可用大括號將該switch段的語句列表括起。
二、迭代語句
選擇語句是根據(jù)表達(dá)式的值選擇語句并執(zhí)行一次,而迭代語句(也叫循環(huán)語句)重復(fù)執(zhí)行語句多次。在循環(huán)的每次迭代中,迭代語句都計(jì)算表達(dá)式的值。開始測試循環(huán)(top-tested loop)在執(zhí)行語句前計(jì)算表達(dá)式的值,而結(jié)束測試循環(huán)(bottom-tested loop)在執(zhí)行語句后計(jì)算表達(dá)式的值。
要提前結(jié)束循環(huán),而不重新計(jì)算表達(dá)式的值,可使用下述跳轉(zhuǎn)語句之一:break、goto、return和throw。continue語句直接進(jìn)行下一次迭代。
2.1 while語句
while語句屬于開始測試循環(huán),它不斷執(zhí)行嵌套的語句,直到boolean-expression為false。由于每次迭代前都計(jì)算表達(dá)式的值,因此嵌套的語句將執(zhí)行零次或多次。
while語句的語法如下:
while ( boolean-expression )
embedded-statement
如果boolean-expression為true,就將執(zhí)行embedded-statement;執(zhí)行完畢后,將重新回到循環(huán)開頭,并再次計(jì)算表達(dá)式的值。
如果 boolean-expression 為 false ,就將接著執(zhí)行 while 語句后面的語句。如果boolean-expression一開始就為false,那么embedded-statement一次也不會(huì)執(zhí)行。
2.2 do語句
do語句也重復(fù)執(zhí)行嵌套的語句,直到boolean-expression為false。不同于while語句,do語句屬于結(jié)束測試循環(huán),因此在計(jì)算boolean-expression前,embedded-statements已執(zhí)行一次。這意味著嵌套的語句至少會(huì)執(zhí)行一次。
do語句的語法如下:
do
embedded-statement
while ( boolean-expression );
如果boolean-expression為true,就將轉(zhuǎn)到循環(huán)開頭再次執(zhí)行embedded-statements;否則,將跳轉(zhuǎn)到do語句后面的語句處繼續(xù)執(zhí)行。
2.3 for語句
for語句可能是被人誤解最深的迭代語句,因?yàn)樗雌饋碜顝?fù)雜,但其基本行為與其他迭代語句相同。它也不斷執(zhí)行嵌套的語句,直到指定的表達(dá)式為false。
for語句的語法如下:
for ( initializer ; condition ; iterator )
embedded-statement
for語句最常用于順序處理數(shù)組。
導(dǎo)致for語句看起來很復(fù)雜的原因是它包含3個(gè)表達(dá)式,這些表達(dá)式都是可選的。表達(dá)式之間必須用分號分隔,即使表達(dá)式省略了也必須如此。
初始化表達(dá)式可初始化一個(gè)局部變量,也可初始化多個(gè)局部變量,在后一種情況下,必須用逗號將變量初始化語句分開。對于在初始化表達(dá)式中聲明的局部變量,其作用域?yàn)闂l件、迭代器和嵌套語句。
ps:初始化表達(dá)式聲明空間
可將整個(gè)for語句視為是在一對看不到的大括號內(nèi)定義的,這對大括號為初始化表達(dá)式定義了局部變量聲明空間。
條件(condition)必須是布爾表達(dá)式,如果省略了它,就認(rèn)為該表達(dá)式為true。
最后,迭代器(iterator)可以是單個(gè)表達(dá)式,也可以是用逗號分隔的表達(dá)式列表,這些表達(dá)式的值通常取決于初始化表達(dá)式中聲明的局部變量。
ps:無限循環(huán)
就像使用while語句可能創(chuàng)建無限循環(huán)一樣,也可使用for語句創(chuàng)建不斷運(yùn)行的循環(huán),方法是省略全部3個(gè)表達(dá)式:
for ( ; ; ; )
{
Console.WriteLine(“l(fā)ine”);
}
while語句和for語句可互換,但是for語句更簡潔。
在for語句中,發(fā)生的事件與while語句相同
- 如果有初始化表達(dá)式,就執(zhí)行它。如果有多個(gè)表達(dá)式,就將按順序執(zhí)行它們。初始化表達(dá)式只在開始執(zhí)行for語句時(shí)執(zhí)行一次。
- 如果條件為true,就跳轉(zhuǎn)到嵌套的語句。
- 執(zhí)行嵌套的語句。
- 執(zhí)行迭代器語句并重新判斷條件。如果條件為false,就跳轉(zhuǎn)到for語句后面的語句。
2.4 foreach語句
foreach語句對數(shù)組或集合中的每個(gè)元素執(zhí)行指定的語句一次。不同于for語句,foreach語句不能用于在集合中添加或刪除元素。
foreach語句的語法如下:
foreach ( type identifier in expression )
embedded-statement
如果expression的類型為數(shù)組,就將執(zhí)行到IEnumberable的隱式轉(zhuǎn)換;如果是集合,它要么實(shí)現(xiàn)了IEnumberable或IEnumberable<T>,要么提供了合適的GetEnumerator方法。
ps:迭代變量
foreach語句中的type和identifier聲明了一個(gè)迭代變量,這是一個(gè)只讀的局部變量,其作用域?yàn)榍短椎恼Z句。
遍歷集合中的元素時(shí),迭代變量指向當(dāng)前元素。
在所有的迭代語句中,只有 foreach 語句沒有包含條件。除非有跳轉(zhuǎn)語句結(jié)束循環(huán),否則將對集合中的每個(gè)元素重復(fù)執(zhí)行嵌套語句一次。對于集合和一維數(shù)組,將從索引零開始按升序遍歷元素。如果 expression 是多維數(shù)組,就將從最右邊的那維開始按升序遍歷,并逐漸移到最左邊的那維。
如果集合沒有任何元素,就將不執(zhí)行嵌套的語句。
如下代碼顯示字符串中的每個(gè)字符,每個(gè)字符占一行
string s = “This is a test.”;
foreach (char c in s)
{
Console.WriteLine(c);
}
三、跳轉(zhuǎn)語句
跳轉(zhuǎn)語句與選擇語句、迭代語句的不同之處在于,它們無條件地跳轉(zhuǎn)到指定位置—跳轉(zhuǎn)語句的目標(biāo)(target)位置。
ps:goto語句
雖然goto語句不常用,但是C#確實(shí)提供了,它跳轉(zhuǎn)到用標(biāo)簽標(biāo)記的地方。goto語句還可跳轉(zhuǎn)到switch語句中特定的case標(biāo)簽或default標(biāo)簽處。
goto語句的語法如下:
goto identifier;
goto case constant-expression;
goto default;
與break和continue語句一樣,goto語句也將導(dǎo)致當(dāng)前語句塊中的后續(xù)語句不被執(zhí)行。
強(qiáng)烈建議在任何情況下都不要使用 goto 語句,因?yàn)樗苋菀诪E用,導(dǎo)致代碼難以理解和維護(hù)。大量使用 goto 語句的代碼常被稱為“意大利面條式”代碼,因?yàn)槌绦蛄鞒叹拖袷且槐P意大利面條。
3.1 break語句
break語句用于退出最近的switch、while、do、for或foreach語句。如果多條這樣的語句相互嵌套,就將只退出最里面的那條語句。
3.2 continue語句
continue語句進(jìn)入最近的while、do、for或foreach語句的下一次迭代。如果多條這樣的語句相互嵌套,continue 語句將只用于最里面的語句,跳過 continue 語句和循環(huán)體末尾之間的所有語句。
continue語句導(dǎo)致for語句的表達(dá)式和迭代器被重新計(jì)算,明白這一點(diǎn)很重要。
3.3 return語句
該語句返回到其所屬成員的調(diào)用方。在return語句中可包含一個(gè)表達(dá)式,這種return語句只能用于返回類型不是void的類成員中。return語句也可不包含表達(dá)式,這種return語句只能用于返回類型為void的類成員中,這包括構(gòu)造函數(shù)和終結(jié)器(finalizer)。