欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C# Assembly.Load案例詳解

 更新時(shí)間:2021年08月31日 18:11:59   作者:未風(fēng)  
這篇文章主要介紹了C# Assembly.Load案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下

 我們?cè)谑褂肅# 語(yǔ)言的Assembly.Load 來加載托管程序集并使用反射功能時(shí),一般需要先通過Assembly.Load(), Assembly.LoadFrom() 等方法將目標(biāo)托管程序集加載到當(dāng)前應(yīng)用程序域中,然后生成對(duì)應(yīng)實(shí)例,最后再進(jìn)行調(diào)用實(shí)例的屬性或者方法。

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

  1. 程序集可能是延遲簽名的。
  2. 程序集可能被CAS 策略保護(hù)。
  3. 宿主程序與目標(biāo)程序集的處理器架構(gòu)不同。
  4. 當(dāng)加載目標(biāo)程序集時(shí),目標(biāo)程序集中的方法可能正在運(yùn)行。 (比如,模塊初始化)
  5. 程序集可能應(yīng)用了綁定策略, 你可能不會(huì)得到你想要的那個(gè)程序集。

我們現(xiàn)在關(guān)注第四種情況,因?yàn)檫@種情況是最常見的。我們思考以下幾個(gè)問題:

1. 為什么目標(biāo)程序集的方法在運(yùn)行時(shí)不允許再加載一次?

準(zhǔn)確地說是為什么在一個(gè)應(yīng)用程序域(AppDomain)中加載后的程序集默認(rèn)不允許再另外一個(gè)應(yīng)用程序域中加載?這是因?yàn)樵诘谝淮渭虞d應(yīng)用程序集時(shí),Assemlby.Load 方法會(huì)將此程序集鎖住,以防止在自己使用過程中應(yīng)用程序集被其他應(yīng)用程序修改(一般指刪除)。這其實(shí)與Win32 API 中的CreateFile 函數(shù)行為類似,我們都知道,在 Windows 中去占用一個(gè)文件最直接、最簡(jiǎn)單的方式就是調(diào)用 CreateFile API 函數(shù)來打開文件。具體請(qǐng)參照:

http://www.dbjr.com.cn/article/221122.htm 

2. Assembly.Load 方法能否實(shí)現(xiàn)在加載目標(biāo)程序集時(shí)不鎖定它?

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

byte[] buffer = System.IO.File.ReadAllBytes(yourFullfileNamePath);

//Load assembly using byte array

Assembly assembly = Assembly.Load(buffer);

后臺(tái)的實(shí)現(xiàn)是暫時(shí)先將目標(biāo)程序集鎖定,然后把程序集內(nèi)容復(fù)制到內(nèi)存中,讀取后將程序集解鎖并從內(nèi)存中加載目標(biāo)程序集的拷貝。

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

string assemblyName = "AssemblyTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=fffb45e56dd478e3";

Assembly ass = Assembly.ReflectionOnlyLoad(assemblyName);

byte[] buffer = System.IO.File.ReadAllBytes(ass.Location);

Assembly assembly = Assembly.Load(buffer);

3. Assembly.Load 方法的緩存

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

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

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

4. 還有其他方案嗎?

CLR 框架略圖:

CLR

因?yàn)槟壳癆ssembly 的加載與卸載是完全由應(yīng)用程序域控制的,一個(gè)程序集只可以通過應(yīng)用程序域加載,只能通過應(yīng)用程序域的卸載而卸載,其他任何方式都不可以!??!

那么我們可以在需要時(shí)將目標(biāo)程序集加載進(jìn)應(yīng)用程序域,不需要時(shí)將應(yīng)用程序域卸載,但是當(dāng)前應(yīng)用程序域的卸載只能通過關(guān)閉程序來實(shí)現(xiàn)。

到目前為止,看似無解了,但是我們忽略了一個(gè)事實(shí),那就是我們可以在當(dāng)前應(yīng)用程序域中創(chuàng)建子應(yīng)用程序域??梢酝ㄟ^在子應(yīng)用程序域中進(jìn)行程序集的加載,或者說只要涉及程序集加載的全部放在子應(yīng)用程序域中,主應(yīng)用程序域中不做任何與程序集加載有關(guān)的事情。

這部分內(nèi)容我就不詳細(xì)介紹了,大家可以參考:

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

5. 我們確實(shí)需要使用Assembly.Load嗎?

因?yàn)锳ssembly.Load 是將整個(gè)程序集以及其相關(guān)的依賴程序集全部加載進(jìn)來,只要有一個(gè)出錯(cuò)就會(huì)導(dǎo)致加載失敗。如果我們只是為了使用當(dāng)前程序集的類型,而不是使用其方法或者屬性的話就完全可以拋棄Assembly.Load 方法。

微軟在.Net Framework 2.0 時(shí)介紹了幾個(gè)新的程序集加載APIs:

Assembly.ReflectionOnlyLoadFrom(String assemblyFile)

Assembly.ReflectionOnlyLoad(byte[] rawAssembly)

Assembly.ReflectionOnlyLoad(String assemblyName)

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

  1. 跳過程序集強(qiáng)命名認(rèn)證。
  2. 跳過程序集CAS策略認(rèn)證。
  3. 跳過處理器架構(gòu)檢查規(guī)則。
  4. 不在目標(biāo)程序中執(zhí)行任何方法,包括構(gòu)造函數(shù)。
  5. 不應(yīng)用任何綁定策略。

使用時(shí)有如下幾個(gè)注意事項(xiàng):

1) CLR 不會(huì)搜索目標(biāo)程序集所依賴的程序集,我們必須通過ReflectionOnlyAssemblyResolve(Assembly.Load 中的對(duì)應(yīng)事件是AssemblyResolve)事件手動(dòng)處理。

2) 不可以在通過ReflectionOnly 方法加載進(jìn)來的程序集執(zhí)行任何方法,包括構(gòu)造函數(shù),只可以獲取程序集的信息和類型。

3) 建議使用Assembly.ReflectionOnlyLoadFrom 方法,但是如果目標(biāo)程序集在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 dependencies
        Type[] types = asm.GetTypes();
        // show reflection only assemblies in current appdomain
        Console.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 產(chǎn)品單元經(jīng)理(Unit Manager) Jason Zander 文章中的內(nèi)容的整理:

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

詳細(xì)請(qǐng)參考: http://www.dbjr.com.cn/article/221129.htm

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

7. 需要牢記的經(jīng)驗(yàn)

1) 只加載自己需要直接調(diào)用的程序集,不加載目標(biāo)程序集內(nèi)部引用的程序集和其他無關(guān)程序集。

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

3) 一旦出現(xiàn)加載錯(cuò)誤,不要顯而易見認(rèn)為是程序集不存在!要檢查程序集加載緩存、是否出現(xiàn)同一程序集被不同應(yīng)用程序域加載情況等。

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

參考鏈接:

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

到此這篇關(guān)于C# Assembly.Load案例詳解的文章就介紹到這了,更多相關(guān)C# Assembly.Load內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#生成二維碼的方法

    C#生成二維碼的方法

    這篇文章主要介紹了C#生成二維碼的方法,包括動(dòng)態(tài)鏈接庫(kù)dll文件的調(diào)用、代碼的實(shí)現(xiàn)與使用示例,非常實(shí)用,需要的朋友可以參考下
    2014-11-11
  • C#執(zhí)行SQL事務(wù)用法實(shí)例

    C#執(zhí)行SQL事務(wù)用法實(shí)例

    這篇文章主要介紹了C#執(zhí)行SQL事務(wù)用法,實(shí)例分析了通過C#中提供的Transaction執(zhí)行SQL事務(wù)的使用技巧,需要的朋友可以參考下
    2015-01-01
  • C#使用RestSharp實(shí)現(xiàn)封裝常用的http請(qǐng)求方法

    C#使用RestSharp實(shí)現(xiàn)封裝常用的http請(qǐng)求方法

    這篇文章主要為大家詳細(xì)介紹了C#如何使用RestSharp實(shí)現(xiàn)封裝常用的http請(qǐng)求方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2024-02-02
  • C#如何實(shí)現(xiàn)dataGridView動(dòng)態(tài)綁定數(shù)據(jù)

    C#如何實(shí)現(xiàn)dataGridView動(dòng)態(tài)綁定數(shù)據(jù)

    這篇文章主要介紹了C#如何實(shí)現(xiàn)dataGridView動(dòng)態(tài)綁定數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • C#讀取文件MD5值的實(shí)現(xiàn)代碼

    C#讀取文件MD5值的實(shí)現(xiàn)代碼

    這篇文章主要介紹了C#讀取文件MD5值的實(shí)現(xiàn)代碼,有了這個(gè)核心代碼,就可以實(shí)現(xiàn)校驗(yàn)文件MD5值的一些程序了,需要的朋友可以參考下
    2014-08-08
  • C# 實(shí)現(xiàn)繪制PDF嵌套表格案例詳解

    C# 實(shí)現(xiàn)繪制PDF嵌套表格案例詳解

    嵌套表格,顧名思義,就是在一張表格中的特定單元格中再插入一個(gè)或者多個(gè)表格,本文將為大家介紹C#繪制PDF嵌套表格的代碼示例,需要的同學(xué)可以參考一下
    2021-11-11
  • Unity實(shí)現(xiàn)簡(jiǎn)單虛擬搖桿

    Unity實(shí)現(xiàn)簡(jiǎn)單虛擬搖桿

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)簡(jiǎn)單虛擬搖桿,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • Unity?UGUI的Dropdown下拉菜單組件使用詳解

    Unity?UGUI的Dropdown下拉菜單組件使用詳解

    這篇文章主要為大家介紹了Unity?UGUI的Dropdown下拉菜單組件使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 簡(jiǎn)單實(shí)現(xiàn)C#異步操作

    簡(jiǎn)單實(shí)現(xiàn)C#異步操作

    這篇文章主要為大家詳細(xì)介紹了C#簡(jiǎn)單實(shí)現(xiàn)異步操作的方法,通過BeginInvoke、EndInvoke的方式實(shí)現(xiàn)異步編程,感興趣的小伙伴們可以參考一下
    2016-02-02
  • c# webapi 配置swagger的方法

    c# webapi 配置swagger的方法

    這篇文章主要介紹了c# webapi 配置swagger的方法,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07

最新評(píng)論