直播中
約定
//一個(gè)典型的用C#寫(xiě)就的HelloWorld程序
using System;
class HelloWorld
{
public static void Main()
{
Console.WriteLine("Hello World !");
}
}
我忘記自己第一次用C#向世界問(wèn)好是在什么時(shí)候了,不過(guò)可以肯定我已經(jīng)打過(guò)招呼了,那時(shí)候用的是beta1版?,F(xiàn)在你可以到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, 以及書(shū)寫(xiě)、編譯、測(cè)試、開(kāi)發(fā) .NET Framework 應(yīng)用程序所需要的一切——文檔、例子、命令行工具和編譯器。安裝之后就可以開(kāi)發(fā)和運(yùn)行C#程序了,不過(guò)一般的建議是:一定要看.Net Framework SDK中所帶的文檔與例子,如果能照著例子再寫(xiě)一遍那就再好不過(guò)了。
當(dāng)我第一次看到C#代碼的時(shí)候,同樣認(rèn)為它很像Java,一個(gè)形象的比喻是:C#和Java是一對(duì)雙胞胎,從語(yǔ)法的角度來(lái)講,它們共同的父親當(dāng)然非C++莫屬(請(qǐng)注意,不是VC++)。對(duì)于一個(gè)學(xué)過(guò)Java語(yǔ)言的人來(lái)說(shuō)(比如說(shuō)在下),要理解這段代碼實(shí)在是太容易了:第一行當(dāng)然是注釋了,C#支持兩種注釋方法,以"http://"開(kāi)始的單行注釋和以"/*"、"*/"配對(duì)使用的多行注釋。第二行(using System)導(dǎo)入了System這個(gè)包(在C#中被稱之為名字空間,Namespace),可以讓我們方便的調(diào)用Microsoft.Net基類庫(kù)System中的所有類,在此例中使用了System名字空間中的"Console"類,用于在控制臺(tái)窗口輸出程序運(yùn)行結(jié)果。如前所述,C#并沒(méi)有內(nèi)置的輸入輸出語(yǔ)句,所有需實(shí)現(xiàn)的功能都完全來(lái)自于.Net基類庫(kù)。這一句的作用就是告訴編譯器去哪里尋找Console類以便調(diào)用。
接下來(lái)聲明了一個(gè)類HelloWorld,這個(gè)類中有一個(gè)特殊的方法Main(),每個(gè)可執(zhí)行文件都需要有一個(gè)入口點(diǎn),在C#中,這個(gè)入口點(diǎn)就是Main()方法,此方法將在程序啟動(dòng)時(shí)被調(diào)用。在這個(gè)方法中,Console是在命名空間System下的一個(gè)類,它表示的是控制臺(tái)。這里調(diào)用其靜態(tài)方法WriteLine()。如同C++一樣,靜態(tài)方法允許我們直接作用于類而非實(shí)例對(duì)象。WriteLine()函數(shù)接受字符串類型的參數(shù)"Hello World !",并把它送入控制臺(tái)顯示。如前所述,C#沒(méi)有自己的類庫(kù),它直接獲取Microsoft.NET系統(tǒng)類庫(kù)。在這里正是通過(guò)獲取Microsoft.NET系統(tǒng)類庫(kù)中的System.Console.WriteLine()來(lái)完成我們想要的控制臺(tái)輸出操作。現(xiàn)在使用記事本來(lái)編寫(xiě)這段代碼,并將它的文件名保存為HelloWorld.cs,其中".cs"是C#源代碼文件的擴(kuò)展名。然后在配置好C#編譯器的命令行環(huán)境里鍵入"csc HelloWorld.cs"編譯文件??梢钥吹骄幾g輸出文件HelloWorld.exe。鍵入HelloWorld執(zhí)行這個(gè)文件可得到下面的輸出:
Hello World !
這就是第一個(gè)C#的程序,我們使用csc.exe來(lái)編譯它,對(duì)于這個(gè)C#編譯器,有如下說(shuō)明:
1. 它是隨.Net Framework SDK免費(fèi)發(fā)布的,可以在DOS命令行被調(diào)用
2. 它的使用方法如下:
csc SourceFile.cs /out:TargetFile.exe
如果不使用輸出參數(shù)指定目標(biāo)文件名,則默認(rèn)輸出為源文件名
3. 一般情況下,它在系統(tǒng)文件夾(Windows或WinNT)下的Microsoft.NET\Framework\v1.0.3705文件夾內(nèi)
4. 如果你安裝了VS.Net,從Visual Studio.NET Tools項(xiàng)目組中可以激活Visual Studio.NET Command Prompt窗口,這是一個(gè)配置好C#編譯器的命令行環(huán)境
5. 使用csc.exe編譯后的C#程序并不是機(jī)器代碼(盡管擁有.exe的后綴名)。如前所述,C#程序只是被編譯成了MSIL代碼。
C#編譯器(csc.exe)編譯后的文件并不是一個(gè)嚴(yán)格意義上的可執(zhí)行文件(并不包含機(jī)器代碼),而是一個(gè)PE(portable executable)格式的文件,雖然它同樣擁有.exe的后綴名。在這個(gè)PE文件中也不僅僅只包含中間語(yǔ)言,在其中還包含有元數(shù)據(jù)(Metadata)和一個(gè)由編譯器添加的目標(biāo)平臺(tái)的標(biāo)準(zhǔn)可執(zhí)行文件頭。
中間語(yǔ)言,確切地說(shuō),應(yīng)該稱為微軟中間語(yǔ)言(Microsoft Intermediate Language,MSIL),是由微軟定義的一種界于源代碼與機(jī)器碼之間的一種語(yǔ)言。在CLR中,它首先會(huì)由特定的語(yǔ)言編譯器將其包裝成exe格式的偽代碼(P代碼)。再由特定的編譯器將其轉(zhuǎn)換為本地代碼執(zhí)行。對(duì)于微軟中間語(yǔ)言,一個(gè)形象的比喻是:如果CLR是操作系統(tǒng)的話,那么微軟中間語(yǔ)言就是.Net平臺(tái)上的ASM匯編語(yǔ)言。它比大多數(shù) CPU 機(jī)器語(yǔ)言更為高級(jí),比如它可以理解對(duì)象類型,并具有創(chuàng)建和初始化對(duì)象、調(diào)用關(guān)于對(duì)象的虛擬方法以及直接操作處理數(shù)組元素的指令。它甚至還具有發(fā)現(xiàn)和捕獲異常情況用于錯(cuò)誤處理的指令。
元數(shù)據(jù)(Metadata)和MSIL共同存在于編譯好的程序文件之中,描述了此程序包含的類型的定義、各種類型的簽名及其它一些數(shù)據(jù),相當(dāng)于以前的類型庫(kù)(Type Library),同時(shí)也記載了此程序所引用到的其它外部類。元數(shù)據(jù)的主要作用是將與代碼有關(guān)的更多的信息提供給CLR?;旧?,元數(shù)據(jù)用于如下各項(xiàng)任務(wù):用于表示CLR用途的信息,如定位和裝載類、內(nèi)存中這些類的實(shí)例、解決調(diào)用、翻譯IL為原始碼、加強(qiáng)安全并設(shè)置運(yùn)行時(shí)上下文邊界。
一個(gè)由C#語(yǔ)言寫(xiě)就的源碼文件在CLR環(huán)境中執(zhí)行的過(guò)程是這樣的:首先由C#編譯器編譯成包含了中間語(yǔ)言和元數(shù)據(jù)的PE文件,當(dāng)我們?cè)谙到y(tǒng)中調(diào)用這個(gè)文件時(shí),CLR會(huì)啟動(dòng)一個(gè)編譯器再將這個(gè)PE文件包含的MSIL代碼轉(zhuǎn)換成為托管的本地代碼。轉(zhuǎn)換MSIL代碼為本地碼的這個(gè)編譯器就叫做JIT編譯器(Just In Time,JITer)。請(qǐng)注意它并不是前面我們用到的C#編譯器。
現(xiàn)在讓我們看看JIT編譯器是如何工作的:當(dāng)PE文件被調(diào)用時(shí),JIE編譯器將其分解為MSIL和元數(shù)據(jù),這時(shí)候MSIL并不直接讓.Net去調(diào)用本地的系統(tǒng)接口,而是指定.Net系統(tǒng)去編譯連接那些需要的CLR DLL,編譯出百分之百的本地代碼。整個(gè)的過(guò)程如下:
當(dāng)一個(gè)類型被裝載時(shí),裝載器創(chuàng)建一個(gè)存根(stub),并使它與類型的每一個(gè)方法相連接。當(dāng)一個(gè)方法第一次被調(diào)用時(shí),存根把控制交給JITer。JITer把MSIL編譯為本地代碼,并且把存根指針指向緩沖本地代碼。已經(jīng)被JITer編譯的方法隨后就直接調(diào)用已經(jīng)產(chǎn)生的本地代碼,減少了JITer編譯和執(zhí)行代碼的時(shí)間。可以看到,JITer并不會(huì)一次性的將所有的MSIL都編譯為本地代碼,而是在我們需要時(shí)才即時(shí)編譯,也就是說(shuō),有些代碼可能從來(lái)都沒(méi)有被編譯過(guò)。很明顯這樣做的好處是既保證了運(yùn)行期的安全性,又不會(huì)損失太多的效率。
這就是一個(gè)C#程序執(zhí)行時(shí)的步驟。整個(gè)過(guò)程是這樣的:
1) 由C#編譯器將源代碼編譯為中間語(yǔ)言
2) 裝入托管代碼,這包括解決內(nèi)存中的名字、表層類(laying out classes ),并且創(chuàng)建JIT編譯所必需的存根。通過(guò)執(zhí)行經(jīng)常性校驗(yàn),包括加強(qiáng)一些訪問(wèn)規(guī)則,類裝載器同樣也增強(qiáng)了安全性
3) 用JITer將 IL轉(zhuǎn)換成原始代碼
4) 裝入元數(shù)據(jù)、校驗(yàn)類型安全和方法的完整性
5) 垃圾收集(GC)和異常處理
6) 描繪和查錯(cuò)服務(wù)
7) 管理線程和上下文以及遠(yuǎn)程管理。
不必全部理解這些概念,在以后的學(xué)習(xí)中將會(huì)一一的體會(huì)到它們的精彩,現(xiàn)在你需要做的(如果你還沒(méi)這么干過(guò)的話),是找到ildasm.exe這個(gè)文件(一般情況下,它會(huì)和csc.exe在同一文件夾中)。顧名思義,這是一個(gè)MSIL的反匯編程序(.Net Framework IL Disassembler),在命令行窗口下輸入ildasm helloworld.exe /out=helloworld.il就會(huì)得到兩個(gè)文件:helloworld.il和helloworld.res。前者包括了反編譯出來(lái)的元數(shù)據(jù)和MSIL代碼,后者則是提取的資源文件。用記事本打開(kāi)helloworld.il文件,可以看到它定義并實(shí)現(xiàn)了一個(gè)繼承自System.Object 的HelloWorld類及兩個(gè)函數(shù):Main()和.ctor()。其中.ctor()是HelloWorld類的構(gòu)造函數(shù)。在這個(gè)文件中還包括元數(shù)據(jù)和其它有關(guān)的信息。如果你覺(jué)得這樣不夠直觀的話,可以在命令行窗口鍵入ildasm helloworld.exe,這樣就可以啟動(dòng)ILDASM 窗口并向我們展示出反編譯后的helloworld.exe文件。
請(qǐng)仔細(xì)將這些代碼看上幾遍,現(xiàn)在理解全部這些內(nèi)容并不重要,但是希望你也能看一下文件中的元數(shù)據(jù),這其中包含所有 Runtime 和編譯器需要的有關(guān)程序集及其模塊、類型和成員(如方法)的信息。
行文至此,我想談一下學(xué)習(xí)。如你所知,在我們所處的環(huán)境中,學(xué)習(xí)總意味著是一個(gè)痛苦的過(guò)程,學(xué)習(xí)一種新知識(shí)好像總是為了自己的某種需求,我并不認(rèn)為這樣有什么不對(duì),但我總覺(jué)著,除了拿到高薪和受人尊敬外,學(xué)習(xí)還應(yīng)該帶給我們更多的快樂(lè)。有些知識(shí)我們現(xiàn)在也許用不著,比如前面談到的一些內(nèi)容,但是我們了解了,就是一件值得高興的事。
智慧本身就是好的,有一天我們都會(huì)死去,追求智慧的道路還會(huì)有人在走著。死掉以后的事我看不到。但在我活著的時(shí)候,想到這件事,心里就高興。 ——王小波
今天是2002年4月7號(hào),再過(guò)三天就是王小波的忌日了,不知道有多少人還會(huì)記得這個(gè)日子,還會(huì)記得這個(gè)人。本文的最后,我向大家推薦小波的作品——每一個(gè)心智成熟的人都應(yīng)該讀一讀小波的文字。在他的雜文隨筆集《沉默的大多數(shù)》中有一句話談到了他作為程序員的一面:
“今晚不把這段C++調(diào)通,老子就不睡了!”
>>>未完,待續(xù)...