使用C#的AssemblyResolve事件動態解析載入失敗的程式集

來源:互聯網
上載者:User

標籤:main   9.png   .com   turn   項目   assembly   dom   file   報錯   

我們知道反射是 依賴注入 模式的基礎,依賴注入要求只在項目中引用定義介面的程式集,而不引用介面實作類別的程式集,因為介面實作類別的程式集應該是通過反射來動態載入的,這樣才能保證介面與其實作類別之間的松耦合。可是有時候我們使用反射動態載入程式集的時候會失敗,因為除非我們手動將介面實作類別的程式集放在項目產生後的bin目錄下,或者是在GAC中,否者.Net Framework並不知道該到哪裡去尋找介面實作類別的dll組件檔。幸運的是我們如果使用 AppDomain.CurrentDomain.AssemblyResolve事件,就可以通過C#代碼來自訂程式集載入邏輯,當C#反射解析程式集失敗的時候,通過執行自訂程式集載入邏輯來找到相應的程式集dll檔案。

 

例如現在我們定義了一個普通的C#類庫項目叫MessageDisplay,如所示

裡面只包含了一個C#類MessageDisplayHelper.cs檔案,MessageDisplayHelper.cs代碼如下:

using System;namespace MessageDisplay{    public class MessageDisplayHelper    {        public string Display()        {            return "This is a message!";        }    }}

 

然後我們定義一個C#控制台程式叫AssemblyResolverConsle:

在這個控制台程式中我們不直接引用MessageDisplay程式集,而是使用反射載入程式集MessageDisplay,然後使用反射動態構造MessageDisplayHelper類。由於我們沒有在控制台程式AssemblyResolverConsle中直接引用MessageDisplay程式集,所以在調用Assembly.Load方法動態載入程式集的時候會失敗,從而觸發AppDomain.CurrentDomain.AssemblyResolve事件。AssemblyResolverConsle控制台程式的Program.cs檔案代碼如下:

using System;using System.Reflection;namespace AssemblyResolverConsle{    class Program    {        static void Main(string[] args)        {            //當程式集通過反射載入失敗的時候會觸發AssemblyResolve事件,這裡註冊AssemblyResolve事件的處理函數為CurrentDomain_AssemblyResolve            AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;            //這裡通過調用Assembly.Load方法反射載入MessageDisplay程式集會失敗,因為本項目中沒有引用該程式集,而且MessageDisplay程式集的dll檔案也不在本項目產生的bin目錄下,也不在GAC中。所以這裡會觸發AssemblyResolve事件,調用處理函數CurrentDomain_AssemblyResolve來嘗試執行自訂程式集載入邏輯,然後處理函數CurrentDomain_AssemblyResolve會為這裡的Assembly.Load方法返回MessageDisplay.dll程式集            var messageDisplayAssembly = Assembly.Load("MessageDisplay");            //使用反射動態調用MessageDisplayHelper類的建構函式            var messageDisplayHelper = messageDisplayAssembly.CreateInstance("MessageDisplay.MessageDisplayHelper");            Console.WriteLine(messageDisplayHelper.ToString());            Console.ReadLine();        }        /// <summary>        /// AssemblyResolve事件的處理函數,該函數用來自訂程式集載入邏輯        /// </summary>        /// <param name="sender">事件引發源</param>        /// <param name="args">事件參數,從該參數中可以擷取載入失敗的程式集的名稱</param>        /// <returns></returns>        private static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)        {            //根據載入失敗程式集的名字找到該程式集並返回            if (args.Name == "MessageDisplay")            {                //我們自訂的程式集載入邏輯知道MessageDisplay程式集在C:\AssemblyResolverConsle\Reference\MessageDisplay.dll這個路徑下,所以這裡載入這個路徑下的dll檔案作為AssemblyResolve事件處理函數的傳回值                return Assembly.LoadFile(@"C:\AssemblyResolverConsle\Reference\MessageDisplay.dll");            }            //如果AssemblyResolve事件的處理函數返回null,說明AssemblyResolve事件的處理函數也無法找到載入失敗的程式集,那麼整個程式就會拋出異常報錯            return null;        }    }}

所以AppDomain.CurrentDomain.AssemblyResolve這個事件,給反射載入程式集失敗提供了一個很好的解決途徑,可以允許開發人員自訂程式集解析邏輯。我們不再需要把一個.Net程式所需要用到的所有dll檔案都要求放到bin目錄下或GAC中,而是可以放在任何位置,通過AppDomain.CurrentDomain.AssemblyResolve事件的處理函數來動態載入。

 

使用C#的AssemblyResolve事件動態解析載入失敗的程式集

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.