程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 減少生成的dll數量,減少生成dll數量

減少生成的dll數量,減少生成dll數量

編輯:C#入門知識

減少生成的dll數量,減少生成dll數量


  在開篇之前我想鄙視我自己一下,這個東西根本不需要去寫,本來已經有東西去實現了,正如我組長說我的,看的開源項目太少了。其實這個東西完全可以用ILMerge來解決。

  然後再說說前言,開發東西久了,總會積累到一定量的Helper或Util,於是都放到一個項目裡面一起編一個dll,用的時候就方便,可是問題來了,像SQLite這種Helper需要帶上它的dll,再多封裝幾個類,附帶的dll就更多了,有時候想單單用一個很簡單的Helper,結果還帶了一大堆不相干的dll,會不爽,而且有種感覺是引用時就單純一個Common.dll就夠了,什麼System.Data.SQLite.dll,System.Data.MySql.dll我都不想帶,在一次使用內嵌資源時給流我靈感,把這堆dll在編譯的時候都放到項目資源中,需要的時候就去加載,這樣就行了。

  單純這個就用到了內嵌資源使用方面的知識,另外一個就是AppDomain對dll加載方面的知識。

  在使用內嵌資源時,要把資源包含在項目裡面,內嵌的資源在屬性頁面上"生成操作"選擇"潛入資源",

  在編碼時要把資源用上,得用流來讀取,通過Assembly的GetManifestResourceStream(string name);方法就可以把資源的流獲取到,流到了就愛干嘛干嘛,代碼如下

 1             Stream s = null;
 2             byte[] dllDatas = null;
 3             try
 4             {
 5                 s = Assembly.GetExecutingAssembly().GetManifestResourceStream("ConsoleApplication2.ClassLibrary1.dll");
 6                 dllDatas = new byte[s.Length];
 7                 s.Read(dllDatas, 0, dllDatas.Length);
 8             }
 9             catch (Exception ex)
10             {
11                 return null;
12             }
13             finally
14             {
15                 if (s != null)
16                 {
17                     s.Close();
18                     s.Dispose();
19                 }
20             } 

dll的流拿到流,使用它的地方就在AppDomain的AssemblyResolve事件,當應用程序域加載外部的程序集時,它會默認往兩個地方找,第一是往.NET Framework的目錄中找,再到應用程序所在目錄中找,所以在默認情況下我們開發的類庫都會跟引用程序放到一個目錄,而經常用到的System.dll才不需要放到引用程序目錄中。那假如需要的dll沒辦法從這兩個地方找到的話,程序會拋出FileNotFoundException異常,這個仍然有辦法解決的,其實在拋出FileNotFoundException異常之前,AppDomain會先觸發AssemblyResolve事件,這個事件會返回這個無法找到的程序集,返回的程序集為空,才會拋FileNotFoundException異常,只要我們注冊了AssemblyResolve事件,在綁定的方法中把dll從資源中取出來,加載上程序集之後,無法在文件目錄中找到的程序集就可以加載到程序域中,程序集中的類可以照常使用

代碼如下

 1 AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
 2 
 3 
 4         static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
 5         {
 6 
 7             Stream s = null;
 8             byte[] dllDatas = null;
 9             try
10             {
11                 s = Assembly.GetExecutingAssembly().GetManifestResourceStream("ConsoleApplication2.ClassLibrary1.dll");
12                 dllDatas = new byte[s.Length];
13                 s.Read(dllDatas, 0, dllDatas.Length);
14             }
15             catch (Exception ex)
16             {
17                 return null;
18             }
19             finally
20             {
21                 if (s != null)
22                 {
23                     s.Close();
24                     s.Dispose();
25                 }
26             }
27             Assembly assembly= AppDomain.CurrentDomain.Load(dllDatas);
28             return assembly;
29         }

  但是存在一個問題,這個AssemblyResolve事件在封裝的Common項目中注冊比較合適,可是AssemblyResolve事件應該是主動調用的,而Common裡面的類全都是被調用的,個人覺得這個AssemlbyResolve事件可以放到Helper類的靜態構造函數裡面,此外也暫時想不出更好辦法,或者這種方式本身不是一個好的方式。

  後續在開發中也發現一個問題,假如這個Common.dll在別的程序集也是通過AssemblyResolve事件被加載到程序域中的時候,這些在Common.dll裡面通過AssemlbyResolve事件加載進來的程序集有問題。此問題還暫時無法解釋,估計要學習一下CLR方面的知識。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved