談談.NET程序集(一)
The Assembly in .NET
by 唐小崇
http://www.cnblogs.com/tangchong
在.NET出現之前, Windows的程序有一些非常困擾人的問題:
1.當安裝一個新的應用程序,有些時候會發現,它莫名其妙地損壞了已安裝的應用程序(事實上是在系統的Win32文件夾內添加了與之前重名的dll文件,導致該dll被覆蓋)。這種困境被稱大家稱為“DLL災難”。
2.大部分的程序安裝會影響到所有的系統部件。比如:要在不同的位置拷貝文件,要在注冊表中添加信息。這個問題在於不能將應用程序作為一個單一的實體,這同時也導致了程序不便於拷貝/備份/部署。
3.安全問題。我們很難去保證程序的運行不會危害用戶。
.NET程序 提出的程序集(Assembly)概念很好的解決了“DLL災難”和部署難的問題,並且也提供一些安全保障。下面就讓我們來談談程序集,程序集並不是一個單一的物理單位,它是由一個或者多個 包含元數據(Metadata)的托管模塊(Managed Module)、一些資源文件 以及 清單 邏輯組成。
一、托管模塊(exe/dll)的相關概念
托管模塊一般以.exe/.dll的形式出現,它們由面向CLR的編譯器生成。它主要包含以下四個部分:
1、PE32/PE32+ header 。標准windows PE 頭文件,主要指定了 該模塊是32還是64位文件。還指定了給模塊是GUI(exe),CUI(exe)或者DLL 其中的一種。
2、CLR header。CLR header 的定義在CorHdr.h文件中。它主要包含CLR版本、模塊入口函數(Main函數)的 MethodDef 元數據、元數據的大小及偏移量、可選的強簽名。
3、Metadata。元數據是以二進制數據組成的塊(a block of binary data)。它中包含3類表,分別是:定義表(definition tables)、引用表(reference tables)、清單表(manifest tables)。由於元數據提供如此完備的信息,使得程序集具有自描述的功能,從而解決了博客開頭的前兩個問題。
·定義表(definition tables) 包含本模塊內定義的 類型,方法,字段,參數,屬性,事件。
·引用表(reference tables) 包含了本模塊所引用的 數據集,模塊,類型,方法,字段,屬性,事件。
·清單表(manifest tables) 是描述整個程序集的表。它包含了程序集中所有文件的名稱以及程序集的版本、文化、出版者、公開導出的類型。
托管模塊通常包含定義表和引用表,而清單表一般給程序集使用的(下文會說到)。
我們可以用 ILDasm.exe來查看這些元數據。
4、IL code。中間代碼,編譯器產生的面向CLR的代碼。在運行時,CLR將其轉換為本地CPU指令。
二、程序集
我們把一個或者多個托管模塊,資源文件 組成一個程序集,同時,它有個專門的文件來保存 清單表元數據,這個清單包含了程序集中所有文件的名稱以及程序集的版本、文化、出版者、公開導出的類型。
一定得注意的是:雖然托管模塊具有我們常見的exe文件形式,但CLR操作的對象是程序集,而不是托管模塊。CLR總是先加載清單文件,然后通過清單文件來獲得其他文件的名稱。雖然程序集可以只包含一個托管模塊文件(exe)但是我們要以程序集為單位來進行操作,而不是一單個托管模塊(exe)作為單位。
·程序集定義了可復用的類型(供其它程序集/模塊 使用)
·程序集以版本號來標識
·程序集里包含安全相關的策略信息。
CLR區分單個托管模塊是否是程序集的方法是:查看它是否包含清單元數據表。
不用單個托管模塊而用程序集做個一個執行單位 的好處是:
1、我們可以把不同作用的類型放在不同的文件(托管模塊)中,在互聯網中,可以以增量的形式下載文件。即需要用的時候再下載該部分文件。
2、我們可以添加各種的資源、數據文件通過連接器鏈接到程序集中,比如Excel表,然后再程序里做好讀取即可。
3、我們可以用不同的語言來生成不同功能的托管模塊,這樣每個語言的優勢就體現出來了。
由於程序集有良好的自描述性,我們在部署(或者用戶拷貝)程序集時,都非常方便。只要直接將程序集的文件拷貝到用戶的磁盤中就好了,CLR會通過清單文件來找到各個所需文件。這樣就避免在win32,注冊表中放置文件,照成風險了。下圖為一個程序集的示例:
圖:程序集示例