首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> C# 入門

C# 控制流程陳述式:選擇與迴圈完整指南

     編輯:C# 入門

第 6 章:控制陳述式

有一種陳述式,你在每種程式語言控制流程陳述式中都可以找到。在這一章中,我介紹 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.Parse(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 類別的靜態 Parse 方法,它回傳字串的第一個字元。

第 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:
        DoMore();
}

在這個例子中,在執行了第一個 case 陳述式的程式碼後,將直接執行到其他的 case 標籤的程式碼,直到一個 break 陳述式退出 switch 程式碼段為止。雖然有時這是一個強大的功能,但它更經常地產生難於發現的缺陷。

可如果你想執行其他的 case 標籤的程式碼,那怎麼辦?有一種辦法,它顯示於清單 6.3 中。

清單 6.3 在 switch 陳述式中使用 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;
}

我已經保留了其中一個 switch 陳述式功能的討論直至結束——事實上你可以使用字串作為常數運算式。這對於 VB 程式設計師,可能聽起來不象是什麼大的新聞,但來自 C 或 C++ 的程式設計師將會喜歡這個新功能。

現在,一個 switch 陳述式可以如以下所示檢查字串常數了。

string strTest = "Chris";
switch (strTest)
{
    case "Chris":
        Console.WriteLine("Hello Chris!");
        break;
}

6.2 迴圈陳述式

當你想重複執行某些陳述式或程式碼段時,依賴迴圈陳述式……

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved