程序集和应用程序域
這兩個(gè)概念是DotNet程序員經(jīng)常見(jiàn)到的,但好多人搞不清它們。雖然MSDN對(duì)它們有相關(guān)的說(shuō)明,但并不是那么容易看懂。在這里灰灰蟲(chóng)根據(jù)自己的理解用簡(jiǎn)單易懂的語(yǔ)言解紹一下它們。
程序集(assembly)
??? “程序集是包含編譯好的、面向.NET Framework的代碼的邏輯單元”
??? 這句話(huà)可以理解如下:
??????? 首先:程序集是代碼的邏輯單元,是邏輯上的概念。它不完全等價(jià)于編譯好的DLL物理文件,但一般我們認(rèn)為靜態(tài)專(zhuān)用程序集與編譯出的DLL文件或EXE文件是一致的。
??????? 其次:它是被編譯好的。它不是項(xiàng)目名稱(chēng)或命名空間,更不是源代碼。
??????? 最后:它是是面向.NET Framework的。意味著它雖然被編譯了,但仍需要依托于.NET Framework來(lái)運(yùn)行。
???
??? 一個(gè)程序集可以是一個(gè)包括元數(shù)據(jù)的DLL或EXE,也可以由多個(gè)文件組成,例如資源文件、元數(shù)據(jù)、DLL和EXE。
???
??? 注意:Win32的DLL(動(dòng)態(tài)鏈接庫(kù))和DotNet中的DLL(程序集文件)的擴(kuò)展名雖然都是DLL,但是二者內(nèi)部的數(shù)據(jù)組織是不一樣的,所以千萬(wàn)不要把二者混為一談。
???
??? 程序集的分類(lèi):
??????? 靜態(tài)程序集和動(dòng)態(tài)程序集:
??????? 靜態(tài)程序集:靜態(tài)程序集包括中間語(yǔ)言元數(shù)據(jù)(MSIL,類(lèi)似于Java字節(jié)碼的東西),以及該程序集的資源(位圖、JPEG 文件、資源文件等)。靜態(tài)程序集存儲(chǔ)硬盤(pán)文件中。
??????? 動(dòng)態(tài)程序集:動(dòng)態(tài)程序集直接從內(nèi)存運(yùn)行并且在執(zhí)行前不存儲(chǔ)到磁盤(pán)上,如ASP.NET 2.0中的網(wǎng)站程序運(yùn)行的時(shí)候產(chǎn)生的是動(dòng)態(tài)程序集。
???????
??????? 專(zhuān)用程序集和共享程序集:
??????? 專(zhuān)用程序集一般附帶在某些軟件上,且只為該軟件提供專(zhuān)用的類(lèi)庫(kù),這些庫(kù)包含的代碼只能用于該應(yīng)用程序。一般專(zhuān)用程序集是與應(yīng)用程序放在同一目錄下的,在部署的時(shí)候與應(yīng)用程序一起復(fù)制到目標(biāo)機(jī)器上即可。
??????? 共享程序集是其他應(yīng)用程序可以使用的公共庫(kù),一般是安裝到系統(tǒng)GAC中。因?yàn)槠渌浖梢栽L(fǎng)問(wèn)共享程序集,所以所有共享程序集必須帶有強(qiáng)名稱(chēng)(由發(fā)行者簽名)。
???
??? 本地應(yīng)用程序目錄可用于存儲(chǔ)專(zhuān)用程序集,所以專(zhuān)用程序集一般不會(huì)有版本沖突問(wèn)題。其他應(yīng)用程序都不會(huì)重寫(xiě)私有的程序集。當(dāng)然,仍可以使用私有程序集的版本號(hào),這樣有助于代碼的修改與管理,但它不是.NET所必須的。這種專(zhuān)用程序集是大多數(shù)程序員所喜歡的,它可以很好地避免DLL Hell的問(wèn)題。但這種專(zhuān)用程序集只能部署在應(yīng)用程序所在的目錄之中,而無(wú)法像以往的Win32 DLL那樣放置在System32目錄中供多個(gè)應(yīng)用程序共享,但有的時(shí)候設(shè)計(jì)人員仍有共享程序集的需求(把程序集部署到GAC目錄中),這樣一來(lái)又帶來(lái)了我們似乎又看到DELL HELL又在慢慢地逼近我們,其實(shí)DLL共享程序集中根本不可能出現(xiàn)DELL HELL。因?yàn)楣蚕沓绦蚣⒉皇呛?jiǎn)單地把私有程序集復(fù)制到GAC所在目錄中,開(kāi)發(fā)人員只能使用相關(guān)工具把強(qiáng)命名程序集(Strong-name Assembly)放在GAC所在目錄中。在GAC中可以允許同名稱(chēng)但是不同版本號(hào)的程序集存在,當(dāng)不同版本的強(qiáng)命名程序集安裝在GAC中后,不同的應(yīng)用程序會(huì)根據(jù)版本號(hào)信息去調(diào)用不同的程序集,這樣就不會(huì)產(chǎn)生DLL程序集沖突的問(wèn)題了。
???
??? 幾個(gè)概念:
?????? DLL Hell(DLL地獄)
??????????? 在過(guò)去Win32程序中,DLL文件可以被安裝在System32目錄中,以供多個(gè)應(yīng)用程序共享。
??????????? 但這種方式給我們帶來(lái)了一個(gè)新的問(wèn)題:DLL文件版本控制的問(wèn)題。如果有兩個(gè)軟件共享同一個(gè)DLL,那如果其中一個(gè)軟件版本升級(jí)后把這個(gè)DLL文件更新至一個(gè)新的版本,那另一個(gè)軟件就無(wú)法再訪(fǎng)問(wèn)原來(lái)的DLL版本了。如果再安裝第三個(gè)軟件,這個(gè)軟件也用到了這個(gè)DLL,但版本比現(xiàn)有的DLL版本還要低的話(huà),那一旦產(chǎn)生DLL覆蓋后那原有的軟件就有可能不能再用了。這就是通常所說(shuō)的DLL DELL。
??????
?????? 強(qiáng)命名程序集(Strong-name Assembly)
??????????? 強(qiáng)命名程序集要求設(shè)計(jì)人員為程序集指定版本號(hào)、區(qū)域、Private Key等信息,CLR則以此信息來(lái)找到正確的程序集。
??????????? 生成Private Key信息:
??????????????? sn -k c:\sgkey.snk??????
??????????? 設(shè)置程序集的信息:
??????????? 其中黃色背景部分已過(guò)時(shí)了。應(yīng)當(dāng)如下設(shè)置:
??
????????????
?????? GAC(Global Assembly Cache-全局程序集緩存)
??????????? GAC可以緩存全局使用的程序集,大多數(shù)共享程序集都安裝在這個(gè)緩存中。它對(duì)應(yīng)至硬盤(pán)上的一個(gè)目錄(C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\GAC),不是所有的程序集文件復(fù)制到這個(gè)目錄中就可以實(shí)現(xiàn)程序集共享的。要放在其中的程序集應(yīng)當(dāng)是強(qiáng)命名的程序集,GAC和強(qiáng)命名程序集實(shí)現(xiàn)的共享程序集才可以擺脫DLL DELL的困擾。
?????????? 將強(qiáng)命名程序集加載至GAC中:
??????????????? gacutil -i E:\Proj\ClassLibrary831\bin\Debug\ClassLibrary831.dll
??????????? 查看GAC中的所有的程序集:
???????????????? gacutil -l???
??????????? 查看GAC中指定的程序集:
???????????????? gacutil -l ClassLibrary831
??????????? 如果您將組成應(yīng)用程序的某個(gè)程序集置于全局程序集緩存中,則將不再能夠通過(guò)使用 xcopy 命令復(fù)制應(yīng)用程序目錄來(lái)復(fù)制或安裝該應(yīng)用程序。您還必須在全局程序集緩存中移動(dòng)該程序集。
???????????
??? 程序集與命名空間的區(qū)別:
??????? 一個(gè)程序集可以包含個(gè)命名空間,一個(gè)命名空間也可以跨越多個(gè)程序集。
??????? 如果說(shuō)命名空間是類(lèi)庫(kù)的邏輯組織形式,那么程序集就是類(lèi)庫(kù)的物理組織形式。只有同時(shí)指定所在命名空間和所在的程序集,才能完全限定類(lèi)型。你要使用一個(gè)外部的類(lèi),必須引用該類(lèi)所在的程序集,并且導(dǎo)入該類(lèi)所在的命名空間。
??????? 現(xiàn)在大家應(yīng)當(dāng)知道我們?cè)谑褂媚硞€(gè)外部的類(lèi)時(shí),為什么要在項(xiàng)目中“添加引用”相關(guān)的DLL文件,而且還要在代碼中加入using ......了吧?
??? 程序集與項(xiàng)目的區(qū)別:
??????? 默認(rèn)的情況下,項(xiàng)目名稱(chēng)和程序集的名稱(chēng)是一致的,但這并不代表二者是一個(gè)東西。
??????? 項(xiàng)目是我們開(kāi)發(fā)過(guò)程中概念,項(xiàng)目是用來(lái)統(tǒng)一管理我們開(kāi)發(fā)過(guò)程的源代碼等信息,創(chuàng)建不同的程序,我們應(yīng)當(dāng)建立不同的項(xiàng)目來(lái)管理。
??????? 程序集是部署與使用中概念,它是我們程序編譯出來(lái)的邏輯結(jié)果,作為靜態(tài)程序集它對(duì)應(yīng)著硬盤(pán)上的DLL文件。
??????? 其實(shí)我們可以改變程序集的名稱(chēng),使它和項(xiàng)目的名稱(chēng)不一致:
??????? 這樣編譯后,我們發(fā)現(xiàn)DLL文件名變?yōu)橹付ǖ某绦蚣Q(chēng)了。
??????? (車(chē)延祿)
應(yīng)用程序域(AppDomain):
??? 在操作系統(tǒng)中,程序和程序之間應(yīng)實(shí)現(xiàn)某種形式的隔離,防止程序和程序之間產(chǎn)生不可預(yù)知的影響,這種隔離是必須的。在DotNet技術(shù)之前,通常采用進(jìn)程來(lái)形成隔離邊界。每一個(gè)應(yīng)用程序被加載到單獨(dú)的進(jìn)程中,每個(gè)進(jìn)程都有其私有的內(nèi)存,運(yùn)行在一個(gè)進(jìn)程中的應(yīng)用程序不能寫(xiě)入另一個(gè)應(yīng)用程序的內(nèi)存,您也不能在兩個(gè)進(jìn)程間進(jìn)行直接調(diào)用。
??? 在.NET結(jié)構(gòu)中,應(yīng)用程序有一個(gè)新的邊界:應(yīng)用程序域。應(yīng)用程序域是一個(gè)用于隔離應(yīng)用程序的“輕量級(jí)分界線(xiàn)”。所謂的“輕量級(jí)”是因?yàn)?span style="color:#993366;">多個(gè)應(yīng)用程序域可以存在于單個(gè)操作系統(tǒng)進(jìn)程中。
??? 應(yīng)用程序域可以確保在一個(gè)域中運(yùn)行的代碼不會(huì)影響進(jìn)程中的其他應(yīng)用程序;能夠在不停止整個(gè)進(jìn)程的情況下停止單個(gè)應(yīng)用程序。
??? 進(jìn)程2321有兩個(gè)應(yīng)用程序域。在應(yīng)用程序域A中,實(shí)例化了對(duì)象1和2,對(duì)象1在程序集1中,對(duì)象2在程序集2中。在進(jìn)程2322中,第二個(gè)應(yīng)用程序域有實(shí)例1。實(shí)例和靜態(tài)成員不能在應(yīng)用程序域之間共享,也不能直接訪(fǎng)問(wèn)另一個(gè)應(yīng)用程序域中的對(duì)象。
???
??? AppDomain類(lèi)用于創(chuàng)建和中斷應(yīng)用程序域,加載和卸載程序集。
??? 常用屬性和方法:
??????? FriendlyName?? 取得應(yīng)用程序域的友好名稱(chēng)
??????? CreateDomain()??? 創(chuàng)建新的應(yīng)用程序域。
??????? ExecuteAssembly() 執(zhí)行應(yīng)用程序域中的程序集。它可用來(lái)執(zhí)行另一個(gè)應(yīng)用程序域中的代碼。
??????? Unload() 執(zhí)行域的正常卸載。只有應(yīng)用程序域中正在運(yùn)行的所有線(xiàn)程都已停止或域中不再有運(yùn)行的線(xiàn)程之后,才卸載該應(yīng)用程序域。
??? 創(chuàng)建應(yīng)用程序域 :
??? class AppDomain1
??? {
??????? public static void Main()
??????? {
???????????? Console.WriteLine("Creating new AppDomain.");
???????????? //創(chuàng)建應(yīng)用程序域
???????????? AppDomain domain = AppDomain.CreateDomain("MyDomain");??
???????????? //顯示當(dāng)前應(yīng)用程序域的友好名稱(chēng)
???????????? Console.WriteLine("Host domain: " + AppDomain.CurrentDomain.FriendlyName);
???????????? //顯示新建應(yīng)用程序域的友好名稱(chēng)
???????????? Console.WriteLine("child domain: " + domain.FriendlyName);
??????? }
??? }
???
??? 卸載應(yīng)用程序域:
??? class AppDomain2
??? {
??????? public static void Main()
??????? {
???????????? Console.WriteLine("Creating new AppDomain.");
???????????? //創(chuàng)建應(yīng)用程序域
???????????? AppDomain domain = AppDomain.CreateDomain("MyDomain", null);
???????????? Console.WriteLine("Host domain: " + AppDomain.CurrentDomain.FriendlyName);
???????????? Console.WriteLine("child domain: " + domain.FriendlyName);
???????????? // 卸載應(yīng)用程序域
???????????? AppDomain.Unload(domain);
???????????? Console.WriteLine("Host domain: " + AppDomain.CurrentDomain.FriendlyName);
???????????? //下面這行代碼會(huì)產(chǎn)生異常,因?yàn)閐omain對(duì)象被卸載了
???????????? Console.WriteLine("child domain: " + domain.FriendlyName);
???????? }
??? }
??? 將程序集加載到應(yīng)用程序域中
??? class AppDomain3
??? {
??????? public static void Main(string[] args)
??????? {
??????????? //取得當(dāng)前應(yīng)用程序域
??????????? AppDomain ad = AppDomain.CurrentDomain;
??????????? //加載ClassLibrary831應(yīng)用程序集
??????????? Assembly a = ad.Load("ClassLibrary831");
??????????? //取得應(yīng)用程序集中的NewClass類(lèi)型
??????????? Type t = a.GetType("ClassLibrary831.NewClass");
??????????? //創(chuàng)建NewClass類(lèi)型的實(shí)例
??????????? object o = Activator.CreateInstance(t);
??????????? //給對(duì)象的屬性賦值
??????????? PropertyInfo p1 = t.GetProperty("MyName");
??????????? PropertyInfo p2 = t.GetProperty("MyInfo");
??????????? p1.SetValue(o, "中國(guó)", null);
??????????? p2.SetValue(o,"China",null);
??????????? //調(diào)用對(duì)象的show方法
??????????? MethodInfo mi = t.GetMethod("show");
??????????? mi.Invoke(o, null);
??????? }
??? }
???
??? 創(chuàng)建一個(gè)新的應(yīng)用程序域,并加載執(zhí)行程序集
??? class Test
??? {
??????? static void Main(string[] args)
??????? {
??????????? AppDomain currentDomain = AppDomain.CurrentDomain;
??????????? Console.WriteLine(currentDomain.FriendlyName);
??????????? //創(chuàng)建新的應(yīng)用程序域
??????????? AppDomain secondDomain = AppDomain.CreateDomain("New AppDomain");
??????????? //在新的應(yīng)用程序域中加載執(zhí)行AssemblyA.exe程序集
??????????? secondDomain.ExecuteAssembly("AssemblyA.exe");
??????? }
?? }
轉(zhuǎn)載于:https://www.cnblogs.com/30ErLi/archive/2010/09/17/1828970.html
總結(jié)
- 上一篇: ref和out的区别
- 下一篇: Maven 的classifier的作用