減小生成的dll數量

  在開篇以前我想鄙視我本身一下,這個東西根本不須要去寫,原本已經有東西去實現了,正如我組長說個人,看的開源項目太少了。其實這個東西徹底能夠用ILMerge來解決。函數

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

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

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

  在編碼時要把資源用上,得用流來讀取,經過Assembly的GetManifestResourceStream(string name);方法就能夠把資源的流獲取到,流到了就愛幹嗎幹嗎,代碼以下code

 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從資源中取出來,加載上程序集以後,沒法在文件目錄中找到的程序集就能夠加載到程序域中,程序集中的類能夠照常使用blog

代碼以下事件

 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方面的知識。開發

相關文章
相關標籤/搜索