《.net程式設計先鋒C#》第六章 控制語句 (轉)
有一種語句,你在每種語言控制流程語句中都可以找到。在這一章中,我介紹了的控制語句,它們分為兩個主要部分:
。選擇語句
。迴圈語句
如果你是C或C++員,很多資訊會讓你感到似曾相似;但是,你必須知道它們還存在著一些差別。
6.1 選擇語句
當運用選擇語句時,你定義了一個控制語句,它的值控制了哪個語句被。在C#中用到兩個選擇語句:
。if 語句
。switch 語句
6.1.1 if 語句
最先且最常用到的語句是 if 語句。內含語句是否被執行取決於布林:
if (布林表示式) 內含語句
當然,也可以有else 分枝,當布林表示式的值為假時,該分枝就被執行:
if (布林表示式) 內含語句 else 內含語句
在執行某些語句之前就檢查一個非零長字串的例子:
if (0 != strTest.Length)
{
}
這是一個布林表示式。(!=表示不等於。) 但是,如果你來自C或者C++,可能會習慣於編寫象這樣的程式碼:
if (strTest.Length)
{
}
這在C#中不再工作,因為 if 語句僅允許布林( bool) 資料型別的結果,而字串的Length屬性返回一個整形(integer)。將出現以下錯誤資訊:
error CS0029: Cannot implicitly convert type 'int' to 'bool' (不能隱式地轉換型別 'int' 為 'bool'。)
上邊是你必須改變的習慣,而下邊將不會再在 if 語句中出現賦值錯誤:
if (nMyValue = 5) ...
正確的程式碼應為
if (nMyValue == 5) ...
因為相等比較由==實行,就象在C和C++中一樣。看以下有用的對比運算子(但並不是所有的資料型別都有效):
== ——如果兩個值相同,返回真。
!= ——如果兩個值不同,返回假。
, >= —— 如果滿足了關係(小於、小於或等於、大於、大於或等於),返回真。
每個運算子是透過過載運算子被執行的,而且這種執行對資料型別有規定。如果你比較兩個不同的型別,對於編譯器,必須存在著一個隱式的轉換,以便自動地建立必要的程式碼。但是,你可以執行一個顯式的型別轉換。
清單 6.1 中的程式碼演示了 if 語句的一些不同的使用場合,同時也演示瞭如何使用字串資料型別。這個程式的主要思想是,確定傳遞給應用程式的第一個引數是否以大寫字母、小寫字母或者數字開始。
清單 6.1 確定字元的形態
1: using System;
2:
3: class NestedIfApp
4: {
5: public static int Main(string[] args)
6: {
7: if (args.Length != 1)
8: {
9: Console.WriteLine("Usage: one argument");
10: return 1; // error level
11: }
12:
13: char chLetter = args[0][0];
14:
15: if (chLetter >= 'A')
16: if (chLetter <= 'Z')
17: {
18: Console.WriteLine("{0} is uppercase",chLetter);
19: return 0;
20: }
21:
22: chLetter = Char.FromString(args[0]);
23: if (chLetter >= 'a' && chLetter <= 'z')
24: Console.WriteLine("{0} is lowercase",chLetter);
25:
26: if (Char.IsDigit((chLetter = args[0][0])))
27: Console.WriteLine("{0} is a digit",chLetter);
28:
29: return 0;
30: }
31: }
始於第7行的第一個 if 語段檢測引數陣列是否只有一個字串。如果不滿足條件,程式就在螢幕上顯示用法資訊,並終止執行。
可以採取多種方法從一個字串中提取出單個字元——既可象第13行那樣利用字元,也可以使用Char類的靜態 FromString 方法,它返回字串的第一個字元。
第16~20行的 if 語句塊使用一個巢狀 的if 語句塊檢查大寫字母。用邏輯“與”運算子(&&)可以勝任小寫字母的檢測,而最後透過使用Char類的靜態IsDigit,就可以完成對數字的檢測。
除了“&&”運算子之外,還有另一個條件邏輯運算子,它就是代表“或”的“¦¦”。兩個邏輯運算子都 是“短路”式的。對於“&&”運算子,意味著如果條件“與”表示式的第一個結果返回一個假值,餘下的條件“與”表示式就不會再被求值了。相對應,“¦¦”運算子當第一個真條件滿足時,它就“短路”了。
我想讓大家理解的是,要減少計算時間,你應該把最有可能使求值“短路”的表示式放在前面。同樣你應該清楚,計算 if 語句中的某些值會存在著替在的危險。
if (1 == 1 ¦¦ (5 == (strLength=str.Length)))
{
Console.WriteLine(strLength);
}
當然,這是一個極其誇張的例子,但它說明了這樣的觀點:第一條語句求值為真,那麼第二條語句就不會被執行,它使變數strLength維持原值。給大家一個忠告:決不要在具有條件邏輯運算子的 if 語句中賦值。
6.1.2 switch 語句
和 if 語句相比,switch語句有一個控制表示式,而且內含語句按它們所關聯的控制表示式的常量執行。
switch (控制表示式)
{
case 常量表示式:
內含語句
default:
內含語句
}
控制表示式所允許的資料型別 為: sbyte, byte, short, ushort, uint, long, ulong, char, string, 或者列舉型別。只要使其它不同資料型別能隱式轉換成上述的任何型別,用它作為控制表示式也很不錯。
switch 語句接以下順序執行:
1、控制表示式求值
2、如果 case 標籤後的常量表示式符合控制語句所求出的值,內含語句被執行。
3、如果沒有常量表示式符合控制語句,在default 標籤內的內含語句被執行。
4、如果沒有一個符合case 標籤,且沒有default 標籤,控制轉向switch 語段的結束端。
在繼續更詳細地探討switch語句之前,請看清單 6.2 ,它演示用 switch語句來顯示一個月的天數(忽略跨年度)
清單 6.2 使用switch語句顯示一個月的天數
1: using System;
2:
3: class FallThrough
4: {
5: public static void Main(string[] args)
6: {
7: if (args.Length != 1) return;
8:
9: int nMonth = Int32.Parse(args[0]);
10: if (nMonth < 1 ¦¦ nMonth > 12) return;
11: int nDays = 0;
12:
13: switch (nMonth)
14: {
15: case 2: nDays = 28; break;
16: case 4:
17: case 6:
18: case 9:
19: case 11: nDays = 30; break;
20: default: nDays = 31;
21: }
22: Console.WriteLine("{0} days in this month",nDays);
23: }
24: }
switch 語段包含於第13~21行。對於C程式設計師,這看起來非常相似,因為它不使用break語句。因此,存在著一個更具生命力的重要差別。你必須加上一個break語句(或一個不同的跳轉語句),因為編譯器會提醒,不允許直達下一部分。
何謂直達?在C(和C++)中,忽略break並且按以下編寫程式碼是完全合法的:
nVar = 1
switch (nVar)
{
case 1:
DoSomething();
case 2:
ore();
}
在這個例子中,在執行了第一個case語句的程式碼後,將直接執行到其它case標籤的程式碼,直到一個break語句退出switch語段為止。儘管有時這是一個強大的功能,但它更經常地產生難於發現的缺陷。
可如果你想執行其它case標籤的程式碼,那怎麼辦? 有一種辦法,它顯示於清單6.3中。
清單 6.3 在swtich語句中使用 goto 標籤 和 goto default
1: using System;
2:
3: class SwitchApp
4: {
5: public static void Main()
6: {
7: Random objRandom = new Random();
8: double dRndNumber = objRandom.NextDouble();
9: int nRndNumber = (int)(dRndNumber * 10.0);
10:
11: switch (nRndNumber)
12: {
13: case 1:
14: //什麼也不做
15: break;
16: case 2:
17: goto case 3;
18: case 3:
19: Console.WriteLine("Handler for 2 and 3");
20: break;
21: case 4:
22: goto default;
23: // everything beyond a goto will be warned as
24: // unreachable code
25: default:
26: Console.WriteLine("Random number {0}", nRndNumber);
27: }
28: }
29: }
在這個例子中,透過Random類產生用於控制表示式的值(第7~9行)。switch語段包含兩個對switch語句有效的跳轉語句。
goto case 標籤:跳轉到所說明的標籤
goto default: 跳轉到 default 標籤
有了這兩個跳轉語句,你可以建立同C一樣的功能,但是,直達不再是自動的。你必須明確地請求它。
不再使用直達功能的更深的含義為:你可任意排列標籤,如把default標籤放在其它所有標籤的前面。為了說明它,我建立了一個例子,故意不結束迴圈:
switch (nSomething)
{
default:
case 5:
goto default;
}
我已經保留了其中一個swich 語句功能的討論直至結束——事實上你可以使用字串作為常量表示式。這對於VB程式設計師,可能聽起來不象是什麼大的新聞,但來自C或C++的程式設計師將會喜歡這個新功能。
現在,一個 switch 語句可以如以下所示檢查字串常量了。
string strTest = "Chris";
switch (strTest)
{
case "Chris":
Console.WriteLine("Hello Chris!");
break;
}
6.2 迴圈語句
當你想重複執行某些語句或語段時,依據當前不同的任務,C#提供4個不同的迴圈語句選擇給你使用:
。 for 語句
。foreach 語句
。 while 語句
。do 語句
6.2.1 for 語句
當你預先知道一個內含語句應要執行多少次時,for 語句特別有用。當條件為真時,常規語法允許重複地執行內含語句(和迴圈表示式):
for (初始化;條件;迴圈) 內含語句
請注意,初始化、條件和迴圈都是可選的。如果忽略了條件,你就可以產生一個死迴圈,要用到跳轉語句(break 或goto)才能退出。
for (;;)
{
break; // 由於某些原因
}
另外一個重點是,你可以同時加入多條由逗號隔開的語句到for迴圈的所有三個引數。例如,你可以初始化兩個變數、擁有三個條件語句,並重復4個變數。
作為C或C++程式設計師,你必須瞭解僅有的一個變化:條件語句必須為布林表示式,就象 if 語句一樣。
清單6.4 包含使用 for 語句的一個例子。它顯示瞭如何計算一個階乘,比使用遞迴函式還要快。
清單 6.4 在for 迴圈裡計算一個階乘
1: using System;
2:
3: class Factorial
4: {
5: public static void Main(string[] args)
6: {
7: long nFactorial = 1;
8: long nComputeTo = Int64.Parse(args[0]);
9:
10: long nCurDig = 1;
11: for (nCurDig=1;nCurDig <= nComputeTo; nCurDig++)
12: nFactorial *= nCurDig;
13:
14: Console.WriteLine("{0}! is {1}",nComputeTo, nFactorial);
15: }
16: }
儘管該例子過於拖沓,但它作為如何使用for 語句的一個開端。首先,我本應在初始化內部宣告變數nCurDig:
for (long nCurDig=1;nCurDig <= nComputeTo; nCurDig++) nFactorial *= nCurDig;
另一種忽略初始化的選擇如下行,因為第10行在for 語句的外部初始化了變數。(記住C#需要初始化變數):
for (;nCurDig <= nComputeTo; nCurDig++) nFactorial *= nCurDig;
另一種改變是把++運算子移到內含語句中:
for ( ;nCurDig <= nComputeTo; ) nFactorial *= nCurDig++;
如果我也想擺脫條件語句,全部要做的是增加一條if 語句,用break 語句中止迴圈:
for (;;)
{
if (nCurDig > nComputeTo) break;
nFactorial *= nCurDig++;
}
除了用於退出for語句的break語句外,你還可以用continue 跳過當前迴圈,並繼續下一次迴圈。
for (;nCurDig <= nComputeTo;)
{
if (5 == nCurDig) continue; // 這行跳過了餘下的程式碼
nFactorial *= nCurDig++;
}
6.2.2 foreach 語句
已經在 語言中存在了很久的一個功能是,透過使用For Each 語句收集列舉。C#透過foreach 語句,也有一個用來收集列舉的命令:
foreach(表示式中的型別識別符號) 內含語句
迴圈變數由型別和識別符號宣告,且表示式與收集相對應。迴圈變數代表迴圈正在為之執行的收集元素。
你應該知道不能賦一個新值給迴圈變數,也不能把它當作ref 或out 引數。這樣引用在內含語句中被執行的程式碼。
你如何說出某些類支援foreach 語句? 簡而言之,類必須支援具有 GetEnumerator()名字的方法,而且由其所返回的結構、類或者介面必須具有public 方法MoveNext() 和public 屬性Current。如果你想知道更多,請閱讀語言參考手冊,它有很多關於這個話題的詳細內容。
對於清單 6.5 中的例子,我恰好偶然選了一個類,實現了所有這些需要。我用它來列舉被定義過的所有的環境變數。
清單 6.5 讀所有的環境變數
1: using System;
2: using System.Collections;
3:
4: class EnvironmentDumpApp
5: {
6: public static void Main()
7: {
8: IDictionary envvars = Environment.GetEnvironmentVariables();
9: Console.WriteLine("There are {0} environment variables declared", envvars.Keys.Count);
10: foreach (String strKey in envvars.Keys)
11: {
12: Console.WriteLine("{0} = {1}",strKey, envvars[strKey].ToString());
13: }
14: }
15: }
對GetEnvironmentVariables的呼叫返回一個IDictionary型別介面,它是由中的許多類實現了的字典介面。透過 IDictionary 介面,可以訪問兩個收集:Keys 和 Values。在這個例子裡,我在foreach語句中使用Keys,接著查詢基於當前key值的值(第12行)。
當使用foreach時,只要注意一個問題:當確定迴圈變數的型別時,應該格外小心。選擇錯誤的型別並沒有受到編譯器的檢測,但它會在執行時受檢測,且會引發一個異常。
6.2.3 while 語句
當你想執行一個內含語句0次或更多次時,while語句正是你所盼望的:
while (條件) 內含語句
條件語句——它也是一個布林表示式 ——控制內含語句被執行的次數。你可以使用 break 和continue語句來控制while語句中的執行語句,它的執行方式同在for語句中的完全相同。
為了舉例while的用法,清單 6.6 說明如何使用一個 StreamReader類輸出C#源到螢幕。
清單 6.6 顯示一個檔案的內容
1: using System;
2: using System.IO;
3:
4: class WhileDemoApp
5: {
6: public static void Main()
7: {
8: StreamReader sr = File.OpenText ("whilesample.cs");
9: String strLine = null;
10:
11: while (null != (strLine = sr.ReadLine()))
12: {
13: Console.WriteLine(strLine);
14: }
15:
16: sr.Close();
17: }
18: }
程式碼開啟檔案 whilesample.cs, 接著當ReadLine 方法返回一個不等於null的值時,就在螢幕上顯示所讀取的值。注意,我在while條件語句中用到一個賦值。如果有更多的用&&和¦¦連線起來的條件語句,我不能保證它們是否會被執行,因為存在著“短路”的可能。
6.2.4 do 語句
C#最後可利用的迴圈語句是do語句。它與while語句十分相似,僅當經過最初的迴圈之後,條件才被驗證。
do
{
內含語句
}
while (條件);
do語句保證內含語句至少被執行過一次,而且只要條件求值等於真,它們繼續被執行。透過使用break語句,你可以迫使執行退出 do 語塊。如果你想跳過這一次迴圈,使用continue語句。
一個如何使用do語句的例子顯示在清單 6.7中。它向請求一個或多個數字,並且當執行程式退出do迴圈後計算平均值。
清單 6.7 在do 迴圈中計算平均值
1: using System;
2:
3: class ComputeAverageApp
4: {
5: public static void Main()
6: {
7: ComputeAverageApp theApp = new ComputeAverageApp();
8: theApp.Run();
9: }
10:
11: public void Run()
12: {
13: double dValue = 0;
14: double dSum = 0;
15: int nNoOfValues = 0;
16: char chContinue = 'y';
17: string strInput;
18:
19: do
20: {
21: Console.Write("Enter a value: ");
22: strInput = Console.ReadLine();
23: dValue = Double.Parse(strInput);
24: dSum += dValue;
25: nNoOfValues++;
26: Console.Write("Read another value?");
27:
28: strInput = Console.ReadLine();
29: chContinue = Char.FromString(strInput);
30: }
31: while ('y' == chContinue);
32:
33: Console.WriteLine("The average is {0}",dSum / nNoOfValues);
34: }
35: }
在這個例子裡,我在靜態 Main函式中例項化 ComputeAverageApp型別的一個物件。它同樣接著呼叫例項的Run方法,該方法包含了計算平均值所有必要的功能。
do 迴圈跨越第19~31行。條件是這樣設定的:分別回答各個問題 “y”,以決定是否要增加另一個值。輸入任何其它字元會引起程式退出 do語塊,且平均值被計算。
正如你可以從提到的例子看出,do語句和while語句差別不太大——僅有的差別就是條件在什麼時候被求值。
6.3 小結
這章解釋瞭如何使用C#中用到的各種選擇和迴圈語句。 if 語句在應用程式中可能是最為常用的語句。當在布林表示式中使用計算時,編譯器會為你留意。但是,你一定要確保條件語句的短路不會阻止必要程式碼的執行。
switch 語句——儘管同樣與C語言的相應部分相似——但也被改善了。直達不再被支援,而且你可以使用字串標籤,對於C程式設計師,這是一種新的用法。
在這一章的最後部分,我說明如何使用for、foreach、while和do語句。語句完成各種需要,包括執行固定次數的迴圈、列舉收集元素和執行基於某些條件的任意次數的語句。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-976374/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- shell程式設計中的控制判斷語句程式設計
- 程式控制語句
- sql語句的程式設計手冊(轉)SQL程式設計
- [.net 物件導向程式設計基礎] (7) 基礎中的基礎——流程控制語句物件程式設計
- java兩個控制語句(轉)Java
- MySQL全面瓦解20:可程式設計性之流程控制語句MySql程式設計
- ASP.NET中的常見33條程式設計語句ASP.NET程式設計
- Java語言程式設計—迴圈語句Java程式設計
- C++程式設計從零開始之語句(轉)C++程式設計
- C# .NET網路程式設計C#程式設計
- IT先鋒研究小組沙龍 (轉)
- flask之控制語句 if 語句與for語句Flask
- 第六章:函數語言程式設計 (fango)函數程式設計Go
- C#教程第四課:迴圈控制語句C#
- shell程式設計之條件語句程式設計
- J2ME偽高手先鋒開講:掃雷遊戲的設計(轉)遊戲
- C#函數語言程式設計C#函數程式設計
- c# winform程式設計轉例C#ORM程式設計
- ASP.NET常用語句(轉載)ASP.NET
- 04 shell程式設計之迴圈語句程式設計
- 02 shell程式設計之條件語句程式設計
- Java 控制語句Java
- .NET併發程式設計-函數語言程式設計程式設計函數
- .NET新平臺程式設計 (轉)程式設計
- 好程式設計師Java教程分享Java的兩種跳轉語句程式設計師Java
- python 控制語句Python
- 複雜控制語句
- 流程控制語句
- PLSQL Language Referenc-PL/SQL控制語句-順序控制語句-NULLSQLNull
- VB程式設計師眼中的C# (轉)程式設計師C#
- Linux Shell指令碼程式設計while語句案例Linux指令碼程式設計While
- 03 shell程式設計之case語句與函式程式設計函式
- C 語言程式設計(unix) (轉)程式設計
- Java程式設計:利用while語句計算10的階乘Java程式設計While
- C#與.NET入門之C# 8.0和.NET Core 3.0高階程式設計C#程式設計
- .NET框架-微軟C#程式設計風格官方指南框架微軟C#程式設計
- C# 網路程式設計:.NET 開發者的核心技能C#程式設計
- 守望先鋒 UI 庫UI