C# 的 Hello World 程式碼非常簡單,如下所示:
class Program
{
static void Main(string[] args)
{
Console.Write("hello, world");
}
}
在 CLR 執行程式碼前,會建立三個應用程式域,其中兩個(系統域和共用域)對於受控代碼是不可見的,它們只能由 CLR 啟動進程建立,而提供 CLR 啟動進程的是 mscoree.dll 和 mscorwks.dll (在多處理器系統下是 mscorsvr.dll) 。第三個則是預設的應用程式域。
系統域負責建立和初始化共用域和預設應用程式域,它將系統庫 mscorlib.dll 載入共用域。
該域還包括了字串駐留池。系統域在進程中保持跟蹤所有域,並實現載入和解除安裝應用程式域的功能。
系統名稱空間的基本型別,如 Object、ValueType、Array、Enum、String、Delegate 等,在 CLR 啟動程式過程中會被預先載入到共用域中。
大部分的程式在執行期間只使用一個域,就是預設的應用程式域。也可以在程式中載入和解除安裝額外的域。
現在,我們已經基本上將程式的編譯和執行的全過程粗糙地瀏覽了一遍。那麼,執行 C# 的 Hello World 程式,需要的基本流程是:
1) 建立控制台專案,編寫程式碼並通過編譯。此時,會生成可執行檔案。這是一個含有 IL 程式碼和後設資料的程式集。
2) 執行這個程式集。因為 Windows 發現它是一個有 PE 檔案頭和 CLR 檔案頭的檔案,於是知道它是 CLR 程式集。通過 CLR 建立系統域和共用域,並載入一個預設的應用程式域。
3) 在該應用程式域中,找到程式的入口點,通過 IL 中的 .entrypoint 即可。
找到入口點之後,使用型別載入器,載入該入口點所在的型別(Program 型別),生成 Program 型別物件(該型別就只有一個成員 Main 和一個 C# 生成的建構函式)。
同時,也生成了 Object 型別物件和 System.Type 型別物件。
生成 Object 型別物件時,用到了 mscorlib,因為 System.Object 是屬於它的型別,但 mscorlib 已經被載入,所以不需要做額外的事情。
4) Helloworld 主程式的 IL 程式碼只有三行,nop 不算。進入 Main 函數,執行程式碼。
5) 通過 ldstr 載入字串 Hello World,字串是屬於 mscorlib 的,且已被載入,故沒問題,將字串壓入棧。
6) 使用 call 呼叫 WriteLine 方法,該方法不在本程式集中,而在 mscorlib 中。我們已經載入了 mscorlib,故沒問題,繼續。
7) 由於我們使用 call 呼叫方法,所以可以在 mscorlib 中找到 WriteLine 方法的 IL 程式碼,這段程式碼其實是 PreJIT 的,所以它的機器碼是現成的。
8) 執行這段機器碼,字串出棧,列印到控制台上。
9) 執行 IL 程式碼 ret,返回,程式結束。
從執行角度看,Helloworld 程式和真正自己編寫的程式相比簡單很多,沒有私有程式集的探測。