日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

你了解 Assembly.Load 吗?

發布時間:2024/6/5 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 你了解 Assembly.Load 吗? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? 我們在使用C# 語言的Assembly.Load 來加載托管程序集并使用反射功能時,一般需要先通過Assembly.Load(), Assembly.LoadFrom() 等方法將目標托管程序集加載到當前應用程序域中,然后生成對應實例,最后再進行調用實例的屬性或者方法。

一般情況下,我們調用Assembly.Load 一類方法是不會出問題的,但是對于以下幾種情況Assembly.Load 方法無法處理:

  • 程序集可能是延遲簽名的。
  • 程序集可能被CAS 策略保護。
  • 宿主程序與目標程序集的處理器架構不同。
  • 當加載目標程序集時,目標程序集中的方法可能正在運行。 (比如,模塊初始化)
  • 程序集可能應用了綁定策略, 你可能不會得到你想要的那個程序集。
  • 我們現在關注第四種情況,因為這種情況是最常見的。我們思考以下幾個問題:

    ?

    1. 為什么目標程序集的方法在運行時不允許再加載一次?

    準確地說是為什么在一個應用程序域(AppDomain)中加載后的程序集默認不允許再另外一個應用程序域中加載?這是因為在第一次加載應用程序集時,Assemlby.Load 方法會將此程序集鎖住,以防止在自己使用過程中應用程序集被其他應用程序修改(一般指刪除)。這其實與Win32 API 中的CreateFile 函數行為類似,我們都知道,在 Windows 中去占用一個文件最直接、最簡單的方式就是調用 CreateFile API 函數來打開文件。具體請參照:

    http://blog.csdn.net/xt_xiaotian/article/details/6362450?

    ?

    2. Assembly.Load 方法能否實現在加載目標程序集時不鎖定它?

    我們可以使用如下代碼加載我們的程序集:

    1: byte[] buffer = System.IO.File.ReadAllBytes(yourFullfileNamePath); 2: //Load assembly using byte array 3: Assembly assembly = Assembly.Load(buffer);

    后臺的實現是暫時先將目標程序集鎖定,然后把程序集內容復制到內存中,讀取后將程序集解鎖并從內存中加載目標程序集的拷貝。

    如果你需要通過上面的方法加載GAC 中的程序集,那么可以通過如下代碼實現:

    1: string assemblyName = "AssemblyTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=fffb45e56dd478e3"; 2: Assembly ass = Assembly.ReflectionOnlyLoad(assemblyName); 3: byte[] buffer = System.IO.File.ReadAllBytes(ass.Location); 4: Assembly assembly = Assembly.Load(buffer);

    ?

    3. Assembly.Load 方法的緩存

    在我們使用Assembly.Load 系列方法加載目標程序集時,可能有各種情況導致加載失敗,最常見的是目標程序集不存在而導致加載失敗問題。失敗后我們可能想要再加載一次或者加載多次直到成功為止,但是在.NET Framework 2.0 以后默認是無法實現的,原因在于.NET Framework 2.0 以后 Assembly.Load 方法有緩存,第一次加載目標程序集的失敗或者成功的狀態都會被緩存,這樣在你下一次加載目標程序集時不會真的加載,會直接從緩存里取目標程序集的內容和狀態。

    對這種情況我們可以在調用Assembly.Load 方法的宿主程序的app.config 中加入如下配置信息來禁用緩存:

    <?xml version="1.0"?> <configuration><runtime><disableCachingBindingFailures enabled="1" /></runtime><startup><supportedRuntime version="v2.0.50727"/></startup> </configuration>

    4. 還有其他方案嗎?

    CLR 框架略圖:

    因為目前Assembly 的加載與卸載是完全由應用程序域控制的,一個程序集只可以通過應用程序域加載,只能通過應用程序域的卸載而卸載,其他任何方式都不可以!!!

    那么我們可以在需要時將目標程序集加載進應用程序域,不需要時將應用程序域卸載,但是當前應用程序域的卸載只能通過關閉程序來實現。

    到目前為止,看似無解了,但是我們忽略了一個事實,那就是我們可以在當前應用程序域中創建子應用程序域。可以通過在子應用程序域中進行程序集的加載,或者說只要涉及程序集加載的全部放在子應用程序域中,主應用程序域中不做任何與程序集加載有關的事情。

    這部分內容我就不詳細介紹了,大家可以參考:

    http://www.codeproject.com/Articles/42312/Loading-Assemblies-in-Separate-Directories-Into-a

    ?

    5. 我們確實需要使用Assembly.Load嗎?

    因為Assembly.Load 是將整個程序集以及其相關的依賴程序集全部加載進來,只要有一個出錯就會導致加載失敗。如果我們只是為了使用當前程序集的類型,而不是使用其方法或者屬性的話就完全可以拋棄Assembly.Load 方法。

    微軟在.Net Framework 2.0 時介紹了幾個新的程序集加載APIs:

    Assembly.ReflectionOnlyLoadFrom(String assemblyFile)

    Assembly.ReflectionOnlyLoad(byte[] rawAssembly)

    Assembly.ReflectionOnlyLoad(String assemblyName)

    基于開篇提到的Assembly.Load 方法的5種問題, Reflection Only程序集加載APIs 可以:

  • 跳過程序集強命名認證。
  • 跳過程序集CAS策略認證。
  • 跳過處理器架構檢查規則。
  • 不在目標程序中執行任何方法,包括構造函數。
  • 不應用任何綁定策略。
  • 使用時有如下幾個注意事項:

    1) CLR 不會搜索目標程序集所依賴的程序集,我們必須通過ReflectionOnlyAssemblyResolve(Assembly.Load 中的對應事件是AssemblyResolve)事件手動處理。

    2) 不可以在通過ReflectionOnly 方法加載進來的程序集執行任何方法,包括構造函數,只可以獲取程序集的信息和類型。

    3) 建議使用Assembly.ReflectionOnlyLoadFrom 方法,但是如果目標程序集在GAC中那么可以使用Assembly.ReflectionOnlyLoad方法。

    具體示例代碼如下:

    using System; using System.IO; using System.Reflection;public class ReflectionOnlyLoadTest {private String m_rootAssembly;public ReflectionOnlyLoadTest(String rootAssembly){m_rootAssembly = rootAssembly;}public static void Main(String[] args){if (args.Length != 1){Console.WriteLine("Usage: Test assemblyPath");return;}try{ReflectionOnlyLoadTest rolt = new ReflectionOnlyLoadTest(args[0]);rolt.Run();}catch (Exception e){Console.WriteLine("Exception: {0}!!!", e.Message);}}internal void Run(){AppDomain curDomain = AppDomain.CurrentDomain;curDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(MyReflectionOnlyResolveEventHandler);Assembly asm = Assembly.ReflectionOnlyLoadFrom(m_rootAssembly);// force loading all the dependenciesType[] types = asm.GetTypes();// show reflection only assemblies in current appdomainConsole.WriteLine("------------- Inspection Context --------------");foreach (Assembly a in curDomain.ReflectionOnlyGetAssemblies()){Console.WriteLine("Assembly Location: {0}", a.Location);Console.WriteLine("Assembly Name: {0}", a.FullName);Console.WriteLine();}}private Assembly MyReflectionOnlyResolveEventHandler(object sender, ResolveEventArgs args){AssemblyName name = new AssemblyName(args.Name);String asmToCheck = Path.GetDirectoryName(m_rootAssembly) + "\\" + name.Name + ".dll";if (File.Exists(asmToCheck)){return Assembly.ReflectionOnlyLoadFrom(asmToCheck);}return Assembly.ReflectionOnlyLoad(args.Name);} }

    6. 為什么沒有Assembly.UnLoad 方法?

    以下是CLR 產品單元經理(Unit Manager) Jason Zander 文章中的內容的整理:

    ? 1) 為了保證 CLR 中代碼所引用的代碼地址都是有效的,必須跟蹤諸如 GC 對象和 COM CCW 之類的特殊應用。否則會出現 Unload 一個 Assembly 后,還有 CLR 對象或 COM 組件使用到這個 Assembly 的代碼或數據地址,進而導致訪問異常。為了避免這種錯誤進行的跟蹤,目前是在 AppDomain 一級進行的,如果要加入 Assembly.Unload 支持,則跟蹤的粒度必須降到 Assembly 一級,這雖然在技術上不是不能實現,但代價太大了。
    ? 2) 如果支持 Assembly.Unload 則必須跟蹤每個 Assembly 的代碼使用到的句柄和對現有托管代碼的引用。例如現在 JITer 在編譯方法時,生成代碼都在一個統一的區域,如果要支持卸載 Assembly 則必須對每個 Assembly 都進行獨立編譯。此外還有一些類似的資源使用問題,如果要分離跟蹤技術上雖然可行,但代價較大,特別是在諸如 WinCE 這類資源有限的系統上問題比較明顯。
    ? 3) CLR 中支持跨 AppDomain 的 Assembly 載入優化,也就是 domain neutral 的優化,使得多個 AppDomain 可以共享一份代碼,加快載入速度。而目前 v1.0 和 v1.1 無法處理卸載 domain neutral 類型代碼。這也導致實現 Assembly.Unload 完整語義的困難性。

    詳細請參考: http://www.cnblogs.com/ccBoy/archive/2004/07/13/23636.html

    http://blogs.msdn.com/b/jasonz/archive/2004/05/31/145105.aspx

    ?

    7. 需要牢記的經驗

    1) 只加載自己需要直接調用的程序集,不加載目標程序集內部引用的程序集和其他無關程序集。

    2) 能使用RefelectionLoad 方法加載的程序集絕不要使用Assembly.Load 方法加載。

    3) 一旦出現加載錯誤,不要顯而易見認為是程序集不存在!要檢查程序集加載緩存、是否出現同一程序集被不同應用程序域加載情況等。

    ?

    至此,我們已經闡述了Assembly.Load 方法的一些特性,你已經了解它了嗎?

    ?

    參考鏈接:

    http://msdn.microsoft.com/en-us/library/t07a3dye(v=vs.71).aspx

    http://blogs.msdn.com/b/junfeng/archive/2004/11/03/252033.aspx

    http://blogs.msdn.com/b/junfeng/archive/2004/08/24/219691.aspx

    http://www.sosuo8.com/article/show.asp?id=2979

    http://msdn.microsoft.com/en-us/library/ms404279.aspx

    http://blog.csdn.net/xt_xiaotian/article/details/6362450

    http://blogs.msdn.com/b/jasonz/archive/2004/05/31/145105.aspx

    http://www.cnblogs.com/ccBoy/archive/2004/07/13/23636.html

    http://www.cnblogs.com/wayfarer/archive/2004/09/29/47896.html

    http://www.codeproject.com/Articles/42312/Loading-Assemblies-in-Separate-Directories-Into-a

    http://msdn.microsoft.com/en-us/library/ms404312.aspx

    轉載于:https://www.cnblogs.com/danielWise/archive/2011/09/07/2170042.html

    總結

    以上是生活随笔為你收集整理的你了解 Assembly.Load 吗?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。