本章開始介紹應用程式的配置與動態載入,本章牽涉的知識點很多,有程式集(Assembly)的概念,反射(Reflection)以及特性(Attribute),最後是應用程式的配置問題。在第一章中已經介紹了程式集的基本概念,並且對程式集的作了一些粗略的介紹,那麼下面就結合實際的代碼或者例子來看一下程式集的真實的面目。在反射中會利用程式集的概念以及反射的原理實現程式集的載入,也就是動態載入程式集。因為在程式中能夠動態載入程式集,所以在應用程式中可以根據設定檔而載入不同的程式集,進而也能讓程式呈現出不同的表現形式。
11.1 程式集(Assembly)
程式集是任何 .NET Framework應用程式的基本構造塊。也就是說一個應用程式可以包含多個程式集,也可以只包含一個程式集。如果一個應用程式只包含一個程式集,那麼這個程式集就是應用程式本身。所以說程式集並不能簡單的說就是應用程式。它在概念上只是一個基本構造塊,這個構造塊可以大到是一個應用程式。小到可以只是為應用程式提供一個字串的資源檔。例如,在產生簡單的C#應用程式時,Visual Studio 建立一個單個可移植可執行 (PE) 檔案即一個 EXE 或 DLL形式,明確地說就是一個程式集。
程式集在概念上是一個邏輯單元,而不是物理單元,也就是說一個程式集在邏輯上是一個整體,可是在實體儲存體上可以是一個檔案,也可以是很多檔案。儲存在單檔案中的程式集稱為單檔案程式集,相對應的另一種情況就稱為多檔案程式集。程式集是完全自我描述性的。程式集本身的內容就能夠完全說明自己的所有特點,而不需要其他的輔助檔案。程式集中應該包含編譯好的、面向.NET Framework的代碼,還可能包含在代碼中用到的一些資源,比如,圖片,字串等。為了實現自描述,程式集還應該包括描述了對應代碼中定義的類型和方法的資料,稱這些資料為類型中繼資料。程式集也包含描述程式集本身的中繼資料,這種組件中繼資料包含在一個稱為資訊清單的地區中,在資訊清單中的中繼資料描述了程式集的版本號碼,地區性等資訊,而且還描述了組成程式集的檔案的列表,包含檔案的名稱一個檔案存放的位置。
程式集與命名空間的關係。命名空間在邏輯上為程式中的每個類型提供了一個劃分。但是並沒有規定這個具體的類型必須儲存到那個程式集中。一個命名空間可能全部存放到一個程式集中,也有可能存放到幾個不同的程式集中。那麼一個程式集可以僅僅只存放一個命名空間的所有類型,也可以存放幾個不同的命名空間的所有類型。所以命名空間與程式集並不存在一一對應的關係。有人做過這樣的一個比喻:命名空間就好像規定了一個人屬於那個族(漢族,回族等),但是沒有規定這個人要住在什麼地方,而程式集就是這個人的居住地。回族可以居住在北京,上海,但是他依然是回族人。反過來北京、上海等地也不僅僅住回族,也可能居住的有其他族的人。這個民族與居住地的比喻很形象的說明了命名空間與程式集的關係。
11.1.1 查看程式集
大多數程式集(比如使用Visual Studio.NET建立的那些)一般都是單檔案程式集,也就是只有一個.exe或者.dll檔案(目前.NET的程式集只有這兩種格式)。在這種情況下,資訊清單(manifest)直接嵌入到單檔案程式集中。但是,你也可以用“程式集產生工具”(Al.exe)來建立多檔案程式集。也可以只建立一個只包含清單的程式集。
程式集的清單可以通過.NET Framework SDK中的一個工具ILDASM可以查看。在vs2008提供的命令視窗中輸入ILDASM,可以啟動ILDASM軟體,11-1所示:
圖11-1
單擊檔案菜單,開啟程式集System.Data.dll(在目錄C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727,不同的電腦目錄可能不同),11-2所示:
圖11-2
在圖11-2中不同的內容使用了不同的圖形符號來顯示,在ILDASM中,所有的圖形符號的含義11-3所示:
圖11-3
點擊圖11-2中的MANIFEST,可以看到圖11-4的介面。
圖11-4
在其中有.module extern kernel32.dll的資訊,這個資訊就是中繼資料,它說明該程式集引用了模組kernel32.dll,還有下面的語句
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.hash = (4E 11 1E C1 95 1B 45 70 B5 AD 39 08 4C D6 91 25 //
12 FF FE BE )
.ver 2:0:0:0
}
這條語句說明該程式集引用了外部的程式集mscorlib.dll,這條語句還列出了程式集mscorlib.dll的版本等資訊。
程式集中除了包含資料清單,還包含了一些被編譯為MSIL語言的代碼。現在來看一下其中的一些代碼。11-5,找到System.Data.AcceptRejectRule.Cascade。
圖11-5
雙擊Cascade,就會出現一個視窗,裡面有下面的一行資訊。
.field public static literal valuetype System.Data.AcceptRejectRule Cascade = int32(0x00000001)
.field首先告訴你這個是AcceptRejectRule的一個資料域,它的值是int32(0x00000001)就是1,另外這個值是公開的(public)、靜態(static)、實值型別(valuetype)等資訊。