C#基礎語言知識--編譯和執行過程(一)

1. 將源代碼編譯成託管模塊
<1>使用支持CLR的任何語言創建源代碼文件。
創建一個Cat.cs文件,內容如下:

using System;
namespace Animal
{
    public class Cat
    {
        public void Print()
        {
            Console.WriteLine("cat");
        }
    }
}

再創建一個Dog.cs文件,內容如下:

using System;
namespace Animal
{
    public class Dog
    {
        public void Print()
        {
            Console.WriteLine("dog");
        }
    }
}

<2>使用對應的編譯器檢查語法和分析源代碼,生成託管模塊。
現在可以將Cat.cs和Dog.cs文件生成相應的模塊,利用csc.exe編譯器
(Microsoft Visual Studio 2010 -> Visual Studio Tools -> Visual Studio Command Prompt(2010)..):
csc /t:module /out:D:\test\Cat.netmodule D:\test\Cat.cs
csc /t:module /out:D:\test\Dog.netmodule D:\test\Dog.cs
這個會在D:\test目錄下生成兩個普通模塊:
Cat.netmodule
Dog.netmodule

以上執行過程如下圖:
這裏寫圖片描述

名詞解釋:

1 CLR
.NET FrameWork的核心是其運行庫執行環境,稱爲公共語言運行庫(Common Language Runtime)。
作用:
(1)CLR是一個類似於JVM的虛擬機,爲微軟的.Net產品提供運行環境。
(2)CLR上實際運行的並不是我們通常所用的編程語言(例如C#、VB等),而是一種字節碼形態的“中間語言”。這意味着只要能將代碼編譯成這種特定的“中間語言”(MSIL),
任何語言的產品都能運行在CLR上。
(3)CLR通常被運行在Windows系統上,但是也有一些非Windows的版本。這意味着.Net也很容易實現“跨平臺”。(至於爲什麼大家的印象中.Net的跨平臺性不如Java,更多的是微軟商業戰略導致的)。
語言支持:
微軟已經爲多種語言開發了基於CLR的編譯器,這些語言包括:C++/CLI、C#、Visual Basic、F#、Iron Python、 Iron Ruby和IL。除此之外,其他的一些公司和大學等機構也位一些語言開發了基於CLR的編譯器,例如Ada、APL、Caml、COBOL、Eiffel、Forth、Fortran、Haskell、Lexicon、LISP、LOGO、Lua、Mercury、ML、Mondrian、Oberon、Pascal、Perl、PHP、Prolog、RPG、Scheme、Smaltak、Tcl/Tk。
CLR爲不同的編程語言提供了統一的運行平臺,在很大程度上對上層開發者屏蔽了語言之間才特性差異。對於CLR來說,不同語言的編譯器(Compiler)就相當於一個這種語言的代碼審查者(Checker),所做的工作就是檢查源碼語法是否正確,然後將源碼編譯成CLR所需要的中間語言(IL)。所以編程語言對於CLR是透明的,也就是說CLR只知道IL的存在,而不知道IL是由哪種語言編譯而來。
功能
(1)基類庫支持 (Base Class Library Support)
(2)內存管理 (Memory Management)
(3)線程管理 (Thread Management)
(4)垃圾回收 (Garbage Collection)
(5)安全性 (Security)
(6)類型檢查 (Type Checker)
(7)異常處理 (Exception Manager)
(8)即使編譯 (JIT)

2 託管模塊
託管模塊是標準的32位Windows可移植執行體(PE32)文件,或者是標準的64位Windows可移植執行體(PE32+)文件,它們都需要CLR才能執行。
託管模塊包括:PE32或PE32+頭、CLR頭、元數據和IL(中間語言)代碼。 下圖爲各個部分的說明:
託管模塊的各個部分

2.1 MSIL/託管代碼
中間語言(Microsoft Intermediate Language MSIL)代碼, 這些代碼並非專門用於任何一種操作系統, 也非專門用於C#,稱爲託管代碼。
編譯器把代碼編譯成中間語言(IL),而不是能直接在你的電腦上運行的機器碼。中間語言(IL)在公共語言運行庫(CLR)中運行,這個運行庫給你的運行代碼提供各種各樣的服務(如內存管理和類型檢查)。 .NET和C#只能產生託管代碼。如果你用這類語言寫程序,那麼所產生的代碼就是託管代碼。
優點
中間語言代碼與Java字節碼共享一種理念:它們都是低級語言,語法很簡單(使用數字代碼,而不是文本代碼),可以非常快速地轉換爲本地機器碼。對於代碼,這種精心設計的通用語法有很重要的優點:平臺無關性、提高性能和語言的互操作性。

2.2 非託管代碼
非託管代碼就是在Visual Studio .NET 2002發佈之前所創建的代碼。例如Visual Basic 6, Visual C++ 6, 最糟糕的是,連那些依然殘存在你的硬盤中、擁有超過15年曆史的陳舊C編譯器所產生的代碼都是非託管代碼。
非託管代碼直接編譯成目標計算機的機械碼,這些代碼只能運行在編譯出它們的計算機上,或者是其它相同處理器或者幾乎一樣處理器的計算機上。非託管代碼不能享受一些運行庫所提供的服務,例如安全和內存管理等。如果非託管代碼需要進行內存管理等服務,就必須顯式地調用操作系統的接口,通常來說,它們會調用Windows SDK所提供的API來實現。
跟Visual Studio平臺的其他編程語言不一樣,Visual C++可以創建非託管程序。當你創建一個項目,並且選擇名字以MFC,ATL或者Win32開頭的項目類型,那麼這個項目所產生的就是非託管程序。

兩者之間的區別:
a. 託管代碼是一種中間語言,運行在CLR上;
a. 非託管代碼被編譯爲機器碼,運行在機器上。

b. 託管代碼獨立於平臺和語言,能更好的實現不同語言平臺之間的兼容;
b. 非託管代碼依賴於平臺和語言。

c. 託管代碼可享受CLR提供的服務(如安全檢測、垃圾回收等),不需要自己完成這些操作;
c. 非託管代碼需要自己提供安全檢測、垃圾回收等操作。

2.2 元數據
元數據概述:元數據是一種二進制信息,用以對存儲在公共語言運行庫可移植可執行文件 (PE) 文件或存儲在內存中的程序進行描述。將您的代碼編譯爲 PE 文件時,便會將元數據插入到該文件的一部分中,而將代碼轉換爲 Microsoft
中間語言 (MSIL)
並將其插入到該文件的另一部分中。在模塊或程序集中定義和引用的每個類型和成員都將在元數據中進行說明。當執行代碼時,運行庫將元數據加載到內存中,並引用它來發現有關代碼的類、成員、繼承等信息。
元數據以非特定語言的方式描述在代碼中定義的每一類型和成員。元數據存儲以下信息: (1)程序集的說明
標識(名稱、版本、區域性、公鑰)。
導出的類型。
該程序集所依賴的其他程序集。
運行所需的安全權限。 (2)類型的說明
名稱、可見性、基類和實現的接口。
成員(方法、字段、屬性、事件、嵌套的類型)。 (3)屬性
修飾類型和成員的其他說明性元素。

2. 將託管模塊合併成程序集
CLR實際不和模塊工作。它和程序集工作。
現將上訴生成的兩個普通模塊合併一個程序集。由於這個程序集是一個被其他程序集加載的,因此,生成的文件名可以爲:Animal.dll。
**csc /out:D:\test\Animal.dll /t:library /addmodule:D:\test\Cat.netmodule;D:\test\Dog.netmodule
執行此命令之後,會在D:\test目錄下生成Animal.dll**
以上執行過程如下圖:
這裏寫圖片描述
編譯器默認將生成的託管代碼轉換成程序集。也就是說,C#編譯器生成的是含有清單的託管模塊。
當清單指出程序集是隻由一個文件過程的時候,對於只有一個託管模塊而且無資源(或數據)文件的項目,程序集就是託管模塊,生成過程中無需執行任何額外的步驟。

上面的各個模塊中:
主模塊(負責人):Animal.dll
普通模塊(成員): Cat.netmodule, Dog.netmodule。
程序集(團隊):由主模塊Animal.dll與普通模塊Cat.netmodule、Dog.netmodule組成。但是在一般情況下我們會將Animal.dll稱爲程序集。特別是在IDE 的visual studio的生成的情況下,因爲在IDE默認生成的dll中,已經將各個模塊包含進dll中,除了dll中,並沒有其他的模塊文件。
在這裏,我們可以運行命令:
csc /out:D:\test\Animal.dll /t:library D:\test\Cat.cs D:\test\Dog.cs直接生成Animal.dll文件
此時將不再生成Cat.netmodule與Dog.netmodule文件;

調用生成的程序集:
創建一個Program.cs文件,內容如下:

using Animal;
public class Program
{

    static void Main(string[] args)
    {
        new Dog().Print();
        new Cat().Print();
    }
}

執行命令:
csc /out:D:\test\Program.exe /R:D:\test\Animal.dll D:\test\Program.cs
將會在D:\test生成Program.exe可運行文件
注意:這裏的Animal.dll文件代表的是一個程序集,如果這個程序集由多個文件組成,必須保證其他文件都存在,否則編譯會失敗。如當程序集由主模塊Animal.dll、普通模塊Cat.netmodule與Dog.netmoudle組成時,必須保證這三個文件同時存在。

在命令行中可以直接執行: Program.exe
輸入結果:
dog
cat

名詞解釋:

程序集是一個或多個模塊/資源文件的邏輯性分組。說白了就是基於.NET平臺的一個 .dll 或者 .exe爲後綴的文件。
一個程序集多個模塊的作用:CLR只會加載被引用到的模塊,沒有引用的模塊不會加載。因此,可以將程序集分爲多個模塊,運行程序時,只要保證有被引用到的模塊存在即可,可以減少加載的程序集文件大小;特別是當程序集是通過網絡傳輸加載時。

//示例:
//修改Program.cs文件,使它不再引用Cat.cs文件中的類型。
using Animal;
public class Program
{

    static void Main(string[] args)
    {
        new Dog().Print();
         // new Cat().Print();
    }
}

重新編譯Program.cs文件:
csc /out:D:\test\Program.exe /R:D:\test\Animal.dll D:\test\Program.cs
現在在D:\test文件夾中具有文件如下:
這裏寫圖片描述
運行Program.exe,結果:
這裏寫圖片描述
現在將Cat.netmodule刪除:
這裏寫圖片描述
運行Program.exe,結果:
這裏寫圖片描述
原因是:CLR並沒有加載Cat.netmodule,因此,就算這個普通模塊不存在也無所謂

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章