C#反射之Assembly.Load,Assembly.LoadFile 與 Assembly.LoadFrom方法介紹

一些關於C#反射的知識,估計也就最多達到使用API的程度,至於要深刻了解,以如今的水平估計很難作到,因此下面此篇文章,以做爲一個階段的總結。緩存

對於反射的總結,我想從如下幾個方面展開,首先是反射程序集,模塊,類的成員以及成員的一些信息;接下來就是動態調用類的成員方法;第三個方面就動態產生程序集,模塊和類以及類的成員。好了,如今就讓咱們從反射各類信息開始吧安全

在C#中,咱們要使用反射,首先要搞清楚如下命名空間中幾個類的關係:測試

System.Reflection命名空間.net

(1)   AppDomain:應用程序域,能夠將其理解爲一組程序集的邏輯容器設計

(2)   Assembly:程序集類code

(3)   Module:模塊類blog

(4)   Type:使用反射獲得類型信息的最核心的類字符串

他們之間是一種從屬關係,也就是說,一個AppDomain能夠包含N個Assembly,一個Assembly能夠包含N個Module,而一個Module能夠包含N個Type.部署

AppDomain這個類咱們等下再來說解。咱們先關注Assembly個類get

在程序中,若是咱們要動態加載一個程序集怎麼辦呢?有幾種方式可使用,分別是Load、LoadFrom和LoadWithPartialName三個Assembly的靜態方法.

先來說解Assembly.Load方法,該方法會有多個重載版本,其中一個就是提供程序集的詳細信息,即程序集的標識,包括程序集的名稱,版本,區域信息,公有密鑰標記,所有都是以一個字符串的形式提供,例如:"MyAssembly,Version=1.0.0.0,culture=zh-CN,PublicKeyToken=47887f89771bc57f」.

那麼,使用Assembly.Load加載程序集的順序是怎樣的呢?首先它會去全局程序集緩存查找,而後到應用程序的根目錄查找,最後會到應用程序的私有路徑查找。

固然,若是你使用的是弱命名程序集,也即只給出程序集的名稱,那麼這個時候,CLR將不會在程序集上應用任何安全或者部署策略,並且Load也不會到全局緩存程序集中查找程序集。

測試加載弱命名程序集的例子以下:

(1)   新建一個控制檯應用程序的工程,同時勾選建立解決方案

(2)   在解決方案中新建一個類庫的項目,隨便寫一個類和一個方法

(3)   在控制檯項目中,首先不添加引用,直接在Main方法中添加以下代碼:

Assembly assembly = Assembly.Load("MyAssembly");

if (assembly != null)

{ Console.WriteLine("加載成功"); }

執行程序,會拋出異常,說找不到該程序集。什麼緣由呢?由於咱們使用的是弱命名程序集,Load方法不會去全局程序集緩存中查找,而該應用程序目錄下又沒有該程序集,因此程序找不到。這個時候,咱們把程序稍微改一下,不用添加代碼,只需添加對MyAssembly的引用,從新運行程序,加載成功了。

接下來,咱們就要看看Load怎麼加載強命名程序集了,這個步驟稍微有些複雜。仍是剛纔的項目,找到MyAssembly.dll程序集所在的目錄,通常在bin"Debug目錄下

(1)生成密鑰對文件   sn –k MyAssemblyKey.keys

你也能夠本身隨便起一個密鑰對文件名

(2)生成公鑰文件

sn –p MyAssemblyKey.keys MyAssemblyPublicKey.PublicKey

注:查看公鑰命令:sn –tp MyAssemblyPublicKey.PublicKey

(3)建立強命名程序集。

很簡單,只須要在聲明命名空間的那句代碼上加上以下特性:

[assembly:AssemblyKeyFileAttribute(@」D:"Test"MyAssemblyKey.keys」)]

(4)   編譯項目

(5)   將程序集添加到程序集全局緩存

gacutil –i MyAssembly.dll

這個時候,轉到加載程序集的項目中,將Load方法中的參數改成」程序集名,Version=版本,culture=區域信息,PublicKeyToken=公鑰「,而後再去掉對程序集的引用,咱們會發現,程序運行成功。代表Load到全局緩存區查找到了該程序集。

使用Load方法加載程序集,特別是強命名程序集,能在程序集上應用安全和部署策略,推薦使用該方法動態加載程序集,至於LoadFrom和LoadWithPartialName。

首先咱們仍是來看看LoadFrom方法,這個方法的原理是這樣的:咱們若是要使用它來動態加載程序集,必須告訴它程序集的路徑,也即在哪一個目錄下面,CLR會去加載與你指定的路徑徹底匹配的程序集。記住,當咱們指定程序集路徑時,不能包括任何關於程序集強命名的信息,因此,CLR不會在咱們指定的程序集文件上應用任何策略,並且也不會去任何其餘的地方搜索程序集,簡言之,它就是指哪打哪,呵呵。

例如:你有個程序集在D:/Test/MyAssembly.dll,你要用Assembly.LoadFrom加載該程序集,代碼就以下:

Assembly assembly = Assembly.LoadFrom(@」D:/Test/MyAssembly.dll」);

對於,LoadWithParitalName方法,推薦你們最好不要使用它,由於程序沒法肯定最終要去加載哪一個程序集的版本,因此咱們這裏只是簡單的介紹一下它的工做原理:你能夠傳遞一個程序集標識給它,包括程序集名稱,至於其餘信息是可選的(區域信息,公有密鑰等),該方法執行時,會首先檢查應用程序中配置文件的qualifyAssembly節點,若是存在,則把該部分名稱的程序集替換成徹底的程序集標識,若是不存在,則使用程序集名稱先到應用程序根目錄下查找,而後是私有目錄,沒有找到的話,就到程序集全局緩存中查找。簡單過程以下:

       應用程序根目錄 -> 應用程序私有目錄 -> 程序集全局緩存.

Assembly.Load()方法,Assembly.LoadFrom()方法,Assembly.LoadFile()方法的區別!

1,Assembly.Load()

這個方法經過程序集的長名稱(包括程序集名,版本信息,語言文化,公鑰標記)來加載程序集的,會加載此程序集引用的其餘程序集,通常狀況下都應該優先使用 這個方法,他的執行效率比LoadFrom要高不少,並且不會形成重複加載的問題(緣由在第2點上說明)

使用這個方法的時候, CLR會應用必定的策略來查找程序集,實際上CLR按以下的順序來定位程序集:

⑴若是程序集有強名稱,在首先在全局程序集緩(GAC)中查找程序集。         

⑵若是程序集的強名稱沒有正確指定或GAC中找不到,那麼經過配置文件中的<codebase>元素指定的URL來查找

⑶若是沒有指定強名稱或是在GAC中找不到,CLR會探測特定的文件夾:

假設你的應用程序目錄是C:/AppDir,<probing>元素中的privatePath指定了一個路徑Path1,你要定位的程序集是AssemblyName.dll則CLR將按照以下順序定位程序集

          C:/AppDir/AssemblyName.dll

          C:/AppDir/AssemblyName/AssemblyName.dll

          C:/AppDir/Path1/AssemblyName.dll

          C:/AppDir/Path1/AssemblyName/AssemblyName.dll

若是以上方法不能找到程序集,會發生編譯錯誤,若是是動態加載程序集,會在運行時拋出異常!

2,Assembly.LoadFrom()

這個方法從指定的路徑來加載程序集,實際上這個方法被調用的時候,CLR會打開這個文件,獲取其中的程序集版本,語言文化,公鑰標記等信息,把他們傳遞給 Load方法,接着,Load方法採用上面的策略來查找程序集。若是找到了程序集,會和LoadFrom方法中指定的路徑作比較,若是路徑相同,該程序集 會被認爲是應用程序的一部分,若是路徑不一樣或Load方法沒有找到程序集,那該程序集只是被做爲一個「數據文件」來加載,不會被認爲是應用程序的一部分。 這就是在第1點中提到的Load方法比LoadFrom方法的執行效率高的緣由。另外,因爲可能把程序集做爲「數據文件」來加載,因此使用 LoadFrom從不一樣路徑加載相同程序集的時候會致使重複加載。固然這個方法會加載此程序集引用的其餘程序集。

3,Assembly.LoadFile()

這個方法是從指定的文件來加載程序集,和上面方法的不一樣之處是這個方法不會加載此程序集引用的其餘程序集!

結論:通常你們應該優先選擇Load方法來加載程序集,若是遇到須要使用LoadFrom方法的時候,最好改變設計而用Load方法來代替!

另:Assembly.LoadFile 與 Assembly.LoadFrom的區別

一、Assembly.LoadFile只載入相應的dll文件,好比Assembly.LoadFile("abc.dll"),則載入abc.dll,假如abc.dll中引用了def.dll的話,def.dll並不會被載入。

Assembly.LoadFrom則不同,它會載入dll文件及其引用的其餘dll,好比上面的例子,def.dll也會被載入。

二、用Assembly.LoadFrom載入一個Assembly時,會先檢查前面是否已經載入過相同名字的Assembly,好比abc.dll有兩個版本(版本1在目錄1下,版本2放在目錄2下),程序一開始時載入了版本1,當使用Assembly.LoadFrom("2//abc.dll")載入版本2時,不能載入,而是返回版本1。Assembly.LoadFile的話則不會作這樣的檢查,好比上面的例子換成Assembly.LoadFile的話,則能正確載入版本2。

LoadFile:加載指定路徑上的程序集文件的內容。LoadFrom: 根據程序集的文件名加載程序集文件的內容。

區別:

LoadFile 方法用來來加載和檢查具備相同標識但位於不一樣路徑中的程序集.但不會加載程序的依賴項。

LoadFrom 不能用於加載標識相同但路徑不一樣的程序集。

 

轉自:http://blog.csdn.net/guxiaoshi/article/details/5009604

相關文章
相關標籤/搜索