雖然我是資深的 Notepad 使用者,但這次我不建議用它來編輯 C# 原始碼。因為 C# 是真正的程式語言,使用 Notepad 編寫程式碼在編譯時可能會產生大量錯誤訊息(C++ 程式設計師一定懂我的意思)。
你有幾種選擇:可以重新配置 Visual C++ 6.0 使其支援 C# 原始檔;第二種選擇是使用全新的 Visual Studio 7;第三,你可以使用任何第三方程式編輯器,最好支援行號、語法著色、工具整合和良好的搜尋功能。CodeWright 就是其中一個例子,如圖 3.1 所示。
當然,上述編輯器沒有一個是建立 C# 程式的必要條件。Notepad 確實可以編輯,但如果你打算撰寫更大型的專案,最好還是投資一個好用的編輯器。
討論編輯器稍微離題,讓我們回到最經典的小型應用程式。最簡短的 C# 版本見清單 3.1。將其儲存為 helloworld.cs,以便依照說明完成編譯等後續步驟。
1: class HelloWorld
2: {
3: public static void Main()
4: {
5: System.Console.WriteLine("Hello World");
6: }
7: }
在 C# 中,程式碼區塊(陳述式群組)由大括號 { 和 } 括住。因此,即使你沒有 C++ 經驗,也能看出 Main() 方法是 HelloWorld 類別陳述式的一部分,因為類別被定義在大括號內。
C# 應用程式(可執行檔)的進入點就是 static Main 方法,它必須包含在一個類別中。只有一個類別能使用該標記定義,除非你告訴編譯器應使用哪一個 Main 方法(否則會產生編譯錯誤)。
與 C++ 相比,Main 的第一個字母是大寫 M,而非小寫。在這個方法中,你的程式開始並結束。方法中可以呼叫其他方法——如這個例子中,用於輸出文字——或者建立物件並啟動該方法。
如你所見,Main 方法回傳 void 型別:
public static void Main()
雖然 C++ 程式設計師看到這些陳述式會感到似曾相識,但其他程式設計師不一定。首先,public 存取修飾詞告訴我們這個方法可以被任何程式存取,這是它被呼叫的必要條件。其次,static 意味著不需先建立類別的實例也能呼叫方法——你只需用類別名稱呼叫方法:
HelloWorld.Main();
不過,我不贊成在 Main 方法中執行這行程式碼,遞迴會導致堆疊溢位。
另一重要面向是回傳型別。對於 Main 方法,可選擇 void(意即完全沒有回傳值),或用 int 為整數結果(應用程式回傳的錯誤層級)。因此,兩種可能的 Main 方法為:
public static void Main()
public static int Main()
C++ 程式設計師同樣知道我要提到的——可以傳給應用程式的命令列參數陣列:
public static void Main(string[] args)
我現在不想詳細說明如何存取參數,但想先給 C++ 程式設計師一個警告:與 C++ 不同,應用程式路徑不是這個陣列的一部分。僅有那些參數包含在這個陣列中。
在對 Main 方法不算簡短的介紹後,讓我們把注意力集中到唯一真正的程式碼行——這行程式碼在螢幕上顯示「Hello World」:
System.Console.WriteLine("Hello World");
假如不是由於有了 System,大家會馬上猜到 WriteLine 是 Console 物件的一個靜態方法。那麼 System 代表什麼呢?它是包含 Console 物件的命名空間(範圍)。實際上並不是每次都要在 Console 物件前加上命名空間的前綴,你可以如清單 3.2 所示範那樣,在應用程式中引入命名空間。
1: using System;
2:
3: class HelloWorld
4: {
5: public static void Main()
6: {
7: Console.WriteLine("Hello World");
8: }
9: }
你只需給 System 命名空間加一個 using 指令。之後,不再需要指定命名空間,就可以使用它們的方法和屬性了。NGWS 框架體系中有很多命名空間,我只對巨大的命名空間池中的少數幾個物件進行探討。但在第八章「用 C# 寫組件」將介紹為你的物件建立自己的命名空間。
由於 NGWS Runtime 支援所有的編譯器(VB、C++ 和 C#),你不必買一個單獨的開發工具把應用程式編譯成 IL(中間語言)。但是,如果你從沒有用過命令列編譯器編譯過應用程式(僅懂得編譯名,而沒有熟記),它還是你的首要選擇。
開啟命令提示字元並切換到存放 helloworld.cs 的目錄。輸入以下命令:
csc helloworld.cs
helloworld.cs 被編譯並連結成 helloworld.exe。因為原始碼沒有錯誤(當然!),C# 編譯器沒有出錯提示,整個編譯過程沒有絲毫停頓,如圖 3.2 所示。
現在你已經準備好執行第一個真正用 C# 撰寫的應用程式。簡單地在命令列上輸入 helloworld,輸出結果為「Hello World」。
在繼續往下介紹之前,我想稍微想像一下第一個應用程式和一個編譯器開關的使用:
csc /out:hello.exe helloworld.cs
這個開關告訴編譯器輸出檔案命名為 hello.exe。雖然這不是什麼絕招,但它是這本書中用到的未來編譯器的基本功能。
到目前為止,我僅示範把簡單的常數字串輸出到螢幕。雖然這本書只介紹 C# 程式設計的概念而不介紹使用者介面程式設計,但我需要讓你迅速學會簡單的螢幕輸入和輸出方法——相當於 C 的 scanf 和 printf,或者 C++ 的 cin 和 cout。我無法提供 VB 相應的函數,因為螢幕存取不是該核心語言的一部分。
你只需要能夠讀取使用者的輸入並提示一些訊息給使用者。清單 3.3 說明如何讀取使用者請求的名字輸入,並顯示一條已定製好的「Hello」訊息。
1: using System;
2:
3: class InputOutput
4: {
5: public static void Main()
6: {
7: Console.Write("Please enter your name: ");
8: string strName = Console.ReadLine();
9: Console.WriteLine("Hello " + strName);
10: }
11: }
第 7 行使用 Console 物件的一個新方法用於提示文字訊息給使用者,它就是 Write 方法。它與 WriteLine 不同的地方在於它輸出時不換行。我使用這種方法以便使用者可以在訊息提示的同一行輸入名字。
在使用者輸入他的名字後(並按 Enter 鍵),ReadLine 方法讀入了一個字串變數。名字字串連接到常數字串「Hello」,並用我們早已熟悉的 WriteLine 方法顯示出來(見圖 3.3)。
你幾乎已學完 NGWS 框架必要的輸入和輸出功能。但是,你還需要為使用者顯示多個值。為使用者寫一個格式化字串。清單 3.4 展示一個例子。
1: using System;
2:
3: class InputOutput
4: {
5: public static void Main()
6: {
7: Console.Write("Please enter your name: ");
8: string strName = Console.ReadLine();
9: Console.WriteLine("Hello {0}", strName);
10: }
11: }
第 9 行包含了使用格式化字串的 Console.WriteLine 陳述式。格式化字串例子如下:
"Hello {0}"
{0} 取代 WriteLine 方法的參數表中緊隨格式化字串後的第一個變數。你可以用該技術格式化超過三個變數:
Console.WriteLine("Hello {0} {1}, from {2}",
strFirstname, strLastname, strCity);
當然,並不僅限於只使用字串變數。你可以使用任何型別,這些型別在後面的第四章「C# 型別」中有討論。
寫程式碼時,你應為程式碼寫註解條文,解釋實作的內容、變更歷史等。雖然你在註解中提供的資訊(如果有的話)是給自己看的,但是你還是必須遵守寫 C# 註解的方法。清單 3.5 顯示採用的兩種不同方式。
1: using System;
2:
3: class HelloWorld
4: {
5: public static void Main()
6: {
7: // 這是單行註解
8: /* 這種註解
9: 跨越多行 */
10: Console.WriteLine(/*"Hello World"*/);
11: }
12: }
// 符號用於單行註解。你可以用 // 註解當前所在行,或是跟在一個程式碼陳述式的後面:
int nMyVar = 10; // 胡說八道
所有在 // 後面的被視為一條註解;所以,你可以同樣用它們來註解一整行或一行原始碼的部分。這種註解方式同 C++ 中介紹的相似。
如果你的註解跨越多行,必須使用 /* */ 的字元組合。這種方式在 C 中有效。除了單行註解外,這種方式在 C++ 和 C# 中也同樣有效。因 C/C++ 和 C# 都使用這種多行註解方式,所以它們也使用相同的終結符。請看下列程式碼行:
/* Console.WriteLine("Hello World"); */
我使用 /* */ 簡單地註解一整行。現在我假定這一行是很長程式碼的一部分,而且我決定要暫時禁用一個程式區塊:
/*
...
/* Console.WriteLine("Hello World"); */
...
*/
這個結構所存在的問題為:「Hello World」那一行後面的 */ 終止了始於第一行的 /* 註解,剩下的程式碼對編譯器有效,你將看到一些有趣的出錯訊息。至少最後的 */ 被標記為歸屬錯誤。我只不過想提醒一下,讓你了解這種錯誤。
在這一章中,你建立、編譯並執行了第一個 C# 應用程式:著名的「Hello World」程式。我用這個短短的應用程式介紹有關 Main 方法,它是一個應用程式的進入點,也是出口點。這個方法可以沒有回傳值或回傳一個整數錯誤層級。如果你的應用程式用參數呼叫,你可以(但不必要)讀出並使用它們。
在編譯和測試應用程式後,你學到了更多由 Console 物件提供的有關輸入和輸出的方法。對於學習 C# 而言,它們足以建立出有意義的主控台範例,但使用者介面的大部分將是 WFC、WinForms 或者 ASP+。