程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#學習筆記(4)

C#學習筆記(4)

編輯:C#入門知識

約定

//一個典型的用C#寫就的HelloWorld程序
using System;
class HelloWorld
{
public static void Main()
{
Console.WriteLine("Hello World !");
}
}

我忘記自己第一次用C#向世界問好是在什麼時候了,不過可以肯定我已經打過招呼了,那時候用的是beta1版。現在你可以到http://msdn.microsoft.com/downloads/default.asp?url=/downloads/sample.asp?url=/msdn-files/027/000/976/msdncompositedoc.xml去下載.Net Framework Software Development Kit (SDK)的正式版,其中包括了前面提到的.NET Framework, 以及書寫、編譯、測試、開發 .NET Framework 應用程序所需要的一切——文檔、例子、命令行工具和編譯器。安裝之後就可以開發和運行C#程序了,不過一般的建議是:一定要看.Net Framework SDK中所帶的文檔與例子,如果能照著例子再寫一遍那就再好不過了。
當我第一次看到C#代碼的時候,同樣認為它很像Java,一個形象的比喻是:C#和Java是一對雙胞胎,從語法的角度來講,它們共同的父親當然非C++莫屬(請注意,不是VC++)。對於一個學過Java語言的人來說(比如說在下),要理解這段代碼實在是太容易了:第一行當然是注釋了,C#支持兩種注釋方法,以"//"開始的單行注釋和以"/*"、"*/"配對使用的多行注釋。第二行(using System)導入了System這個包(在C#中被稱之為名字空間,Namespace),可以讓我們方便的調用Microsoft.Net基類庫System中的所有類,在此例中使用了System名字空間中的"Console"類,用於在控制台窗口輸出程序運行結果。如前所述,C#並沒有內置的輸入輸出語句,所有需實現的功能都完全來自於.Net基類庫。這一句的作用就是告訴編譯器去哪裡尋找Console類以便調用。
接下來聲明了一個類HelloWorld,這個類中有一個特殊的方法Main(),每個可執行文件都需要有一個入口點,在C#中,這個入口點就是Main()方法,此方法將在程序啟動時被調用。在這個方法中,Console是在命名空間System下的一個類,它表示的是控制台。這裡調用其靜態方法WriteLine()。如同C++一樣,靜態方法允許我們直接作用於類而非實例對象。WriteLine()函數接受字符串類型的參數"Hello World !",並把它送入控制台顯示。如前所述,C#沒有自己的類庫,它直接獲取Microsoft.NET系統類庫。在這裡正是通過獲取Microsoft.NET系統類庫中的System.Console.WriteLine()來完成我們想要的控制台輸出操作。現在使用記事本來編寫這段代碼,並將它的文件名保存為HelloWorld.cs,其中".cs"是C#源代碼文件的擴展名。然後在配置好C#編譯器的命令行環境裡鍵入"csc HelloWorld.cs"編譯文件。可以看到編譯輸出文件HelloWorld.exe。鍵入HelloWorld執行這個文件可得到下面的輸出:

Hello World !

這就是第一個C#的程序,我們使用csc.exe來編譯它,對於這個C#編譯器,有如下說明:
1. 它是隨.Net Framework SDK免費發布的,可以在DOS命令行被調用
2. 它的使用方法如下:
  csc SourceFile.cs /out:TargetFile.exe
  如果不使用輸出參數指定目標文件名,則默認輸出為源文件名
3. 一般情況下,它在系統文件夾(Windows或WinNT)下的Microsoft.NETFrameworkv1.0.3705文件夾內
4. 如果你安裝了VS.Net,從Visual Studio.NET Tools項目組中可以激活Visual Studio.NET Command Prompt窗口,這是一個配置好C#編譯器的命令行環境
5. 使用csc.exe編譯後的C#程序並不是機器代碼(盡管擁有.exe的後綴名)。如前所述,C#程序只是被編譯成了MSIL代碼。

C#編譯器(csc.exe)編譯後的文件並不是一個嚴格意義上的可執行文件(並不包含機器代碼),而是一個PE(portable executable)格式的文件,雖然它同樣擁有.exe的後綴名。在這個PE文件中也不僅僅只包含中間語言,在其中還包含有元數據(Metadata)和一個由編譯器添加的目標平台的標准可執行文件頭。

中間語言,確切地說,應該稱為微軟中間語言(Microsoft Intermediate Language,MSIL),是由微軟定義的一種界於源代碼與機器碼之間的一種語言。在CLR中,它首先會由特定的語言編譯器將其包裝成exe格式的偽代碼(P代碼)。再由特定的編譯器將其轉換為本地代碼執行。對於微軟中間語言,一個形象的比喻是:如果CLR是操作系統的話,那麼微軟中間語言就是.Net平台上的ASM匯編語言。它比大多數 CPU 機器語言更為高級,比如它可以理解對象類型,並具有創建和初始化對象、調用關於對象的虛擬方法以及直接操作處理數組元素的指令。它甚至還具有發現和捕獲異常情況用於錯誤處理的指令。

元數據(Metadata)和MSIL共同存在於編譯好的程序文件之中,描述了此程序包含的類型的定義、各種類型的簽名及其它一些數據,相當於以前的類型庫(Type Library),同時也記載了此程序所引用到的其它外部類。元數據的主要作用是將與代碼有關的更多的信息提供給CLR。基本上,元數據用於如下各項任務:用於表示CLR用途的信息,如定位和裝載類、內存中這些類的實例、解決調用、翻譯IL為原始碼、加強安全並設置運行時上下文邊界。

一個由C#語言寫就的源碼文件在CLR環境中執行的過程是這樣的:首先由C#編譯器編譯成包含了中間語言和元數據的PE文件,當我們在系統中調用這個文件時,CLR會啟動一個編譯器再將這個PE文件包含的MSIL代碼轉換成為托管的本地代碼。轉換MSIL代碼為本地碼的這個編譯器就叫做JIT編譯器(Just In Time,JITer)。請注意它並不是前面我們用到的C#編譯器。
現在讓我們看看JIT編譯器是如何工作的:當PE文件被調用時,JIE編譯器將其分解為MSIL和元數據,這時候MSIL並不直接讓.Net去調用本地的系統接口,而是指定.Net系統去編譯連接那些需要的CLR DLL,編譯出百分之百的本地代碼。整個的過程如下:
當一個類型被裝載時,裝載器創建一個存根(stub),並使它與類型的每一個方法相連接。當一個方法第一次被調用時,存根把控制交給JITer。JITer把MSIL編譯為本地代碼,並且把存根指針指向緩沖本地代碼。已經被JITer編譯的方法隨後就直接調用已經產生的本地代碼,減少了JITer編譯和執行代碼的時間。可以看到,JITer並不會一次性的將所有的MSIL都編譯為本地代碼,而是在我們需要時才即時編譯,也就是說,有些代碼可能從來都沒有被編譯過。很明顯這樣做的好處是既保證了運行期的安全性,又不會損失太多的效率。

這就是一個C#程序執行時的步驟。整個過程是這樣的:
1) 由C#編譯器將源代碼編譯為中間語言
2) 裝入托管代碼,這包括解決內存中的名字、表層類(laying out classes ),並且創建JIT編譯所必需的存根。通過執行經常性校驗,包括加強一些訪問規則,類裝載器同樣也增強了安全性
3) 用JITer將 IL轉換成原始代碼
4) 裝入元數據、校驗類型安全和方法的完整性
5) 垃圾收集(GC)和異常處理
6) 描繪和查錯服務
7) 管理線程和上下文以及遠程管理。

不必全部理解這些概念,在以後的學習中將會一一的體會到它們的精彩,現在你需要做的(如果你還沒這麼干過的話),是找到ildasm.exe這個文件(一般情況下,它會和csc.exe在同一文件夾中)。顧名思義,這是一個MSIL的反匯編程序(.Net Framework IL Disassembler),在命令行窗口下輸入ildasm helloworld.exe /out=helloworld.il就會得到兩個文件:helloworld.il和helloworld.res。前者包括了反編譯出來的元數據和MSIL代碼,後者則是提取的資源文件。用記事本打開helloworld.il文件,可以看到它定義並實現了一個繼承自System.Object 的HelloWorld類及兩個函數:Main()和.ctor()。其中.ctor()是HelloWorld類的構造函數。在這個文件中還包括元數據和其它有關的信息。如果你覺得這樣不夠直觀的話,可以在命令行窗口鍵入ildasm helloworld.exe,這樣就可以啟動ILDASM 窗口並向我們展示出反編譯後的helloworld.exe文件。

請仔細將這些代碼看上幾遍,現在理解全部這些內容並不重要,但是希望你也能看一下文件中的元數據,這其中包含所有 Runtime 和編譯器需要的有關程序集及其模塊、類型和成員(如方法)的信息。

行文至此,我想談一下學習。如你所知,在我們所處的環境中,學習總意味著是一個痛苦的過程,學習一種新知識好像總是為了自己的某種需求,我並不認為這樣有什麼不對,但我總覺著,除了拿到高薪和受人尊敬外,學習還應該帶給我們更多的快樂。有些知識我們現在也許用不著,比如前面談到的一些內容,但是我們了解了,就是一件值得高興的事。

智慧本身就是好的,有一天我們都會死去,追求智慧的道路還會有人在走著。死掉以後的事我看不到。但在我活著的時候,想到這件事,心裡就高興。 ——王小波

今天是2002年4月7號,再過三天就是王小波的忌日了,不知道有多少人還會記得這個日子,還會記得這個人。本文的最後,我向大家推薦小波的作品——每一個心智成熟的人都應該讀一讀小波的文字。在他的雜文隨筆集《沉默的大多數》中有一句話談到了他作為程序員的一面:
“今晚不把這段C++調通,老子就不睡了!”


>>>未完,待續...

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved