【转】C#开发奇技淫巧三:把dll放在不同的目录让你的程序更整洁
轉自:https://www.cnblogs.com/marvin/p/PutDllToSpecificFolder.html?utm_source=tuicool&utm_medium=referral
?
系列文章
- C#開發奇技淫巧一:調試windows系統服務
- C#開發奇技淫巧二:根據dll文件加載C++或者Delphi插件
- C#開發奇技淫巧三:把dll放在不同的目錄讓你的程序更整潔
程序目錄的整理
想必C#的開發者都遇到過這個問題,引用的dll都放在根目錄下,隨著項目的日益增大,根目錄下充滿了各種各樣的dll,非常的不美觀。
如果能夠把dll按照想要的目錄來存放,那么系統就美觀多了,以下是我常用的程序各文件的分布:
- 【3rdLibs】
- NLog.dll
- Newtonsoft.Json.dll
- ……
- 【MyLibs】
- 【Resources】
- 【Images】
- Excecutable.exe
- Excecuteble.exe.config
網上有很多的文章述說這個,比如使用Assembly.Load,但是沒有說明在程序中怎么使用,也沒有給出具體的代碼。這里我結合自己多年的實踐經驗,再把整個流程和方法詳細敘述一遍,以便各位看官有個具體的體會。
系統搜索dll的目錄以及順序
CLR解析一個程序集會在一個根目錄內進行搜索,整個探索過程又稱Probing,這個根目錄很顯然就是當前包含當前程序集的目錄。
AppDomainSetup這個類存儲著探索目錄的信息,其成員包括:ApplicationBase、PrivateBinPath。
程序搜索dll的順序如下(區分強名稱簽名的和沒有強名稱簽名的程序集):
沒有做強名稱簽名的程序集:
- 程序的根目錄
- 根目錄下面,與被引用程序集同名的子目錄
- 根目錄下面被明確定義為私有目錄的子目錄
- 在目錄中查找的時候,如果dll查找不到,則會嘗試查找同名的exe
- 如果程序集帶有區域性,而不是語言中立的,則還會嘗試查找以語言區域命名的子目錄
具有強名稱簽名的程序集:
- 全局程序集緩存
- 如果有定義codebase,則以codebase定義為準,如果codebase指定的路徑找不到,則直接報告錯誤
- 程序的根目錄
- 根目錄下面,與被引用程序集同名的子目錄
- 根目錄下面被明確定義為私有目錄的子目錄
- 在目錄中查找的時候,如果dll查找不到,則會嘗試查找同名的exe
- 如果程序集帶有區域性,而不是語言中立的,則還會嘗試查找以語言區域命名的子目錄
如何讓程序識別不同目錄下的dll?
我們看到,上面的順序無論是否有強名稱簽名看,都提到了一個名詞“私有目錄”
方法一:配置App.config文件的privatePath——【推薦】
這是最簡單的方法,當然也有一定的局限性,就是沒法對dll做控制,另外,無法解決第三方DllImprt中引入的程序集不在根目錄下的問題,不過無論怎么說,這個都基本解決了問題。
配置如下,多個目錄用;分隔
<runtime><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><probing privatePath="3rdLib;MyLibs;SubFolder\Sub.dll"/></assemblyBinding> </runtime>方法二:訂閱程序集解析事件AssemblyResolve在代碼中解析
應用程序集域中支持在程序集解析時的處理:AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;。通過這個事件,我們可以在程序集解析時,根據不同的程序集做不用的處理,比如加載x86的程序集還是64位的程序集,當然也就可以指定程序集目錄了
這也正是Assembly.Load和Assembly.LoadFrom等方法的用武之地。
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {AssemblyName assemblyName = new AssemblyName(args.Name);return Assembly.LoadFrom(Path.Combine(baseDirectory, "3rdLibs")); }方法三:在加載使用到dll的代碼之前設置重置當前環境的目錄
這個方法就是通過Environment.CurrentDirectory=customPath,這樣,在調用dll方法時,因為目錄已經切換到了
這是一個取巧的方法,不是很實用,要來回切換程序集目錄,但是在某些情況下非常好用
如何處理[dllImport]中的程序集的加載
自己寫dllImport
如果是自己寫,那么久好控制了,可以直接指定相對的目錄DllImport(3rdLibs\NLog.dll)。不過這種方法不一定可靠,在某些系統硬是加載不了,如果使用了dllImport還是,推薦下面的另外一種方法。
引用的C#的插件又使用了dllImport
這是很多文章都沒有提及的:
因為無法更改路徑,那么只能夠使用上述特殊的方法,更改當前程序的路徑
當然,還有更省事一點的做法,就是在系統環境中,增加一條記錄,指向要加載的dll的所在目錄。因為C++的代碼中,Windows目錄和Windows\System32目錄以及環境變量設定的目錄都是搜索路徑之一。
這里提供怎么從C#中修改系統環境變量的代碼:
static void AddEnvironmentPaths(IEnumerable<string> paths) {var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? string.Empty }; string newPath = string.Join(Path.PathSeparator.ToString(), path.Concat(paths)); Environment.SetEnvironmentVariable("PATH", newPath); }參考文章
- 淺談.NET中程序集的動態加載
- 再談CLR查找和加載程序集的方式,查找程序集
- 深入理解CLR類加載機制
- C#程序集加載方法
?
?
如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力!如果您想持續關注我的文章,請掃描二維碼,關注馬非碼的微信公眾號,我會將我的文章推送給您,并和您一起分享我日常閱讀過的優質文章。本文版權歸作者和博客園共有,來源網址:http://www.cnblogs.com/marvin/歡迎各位轉載,但是未經作者本人同意,轉載文章之后必須在文章頁面明顯位置給出作者和原文連接,否則保留追究法律責 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的【转】C#开发奇技淫巧三:把dll放在不同的目录让你的程序更整洁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信可以还民生信用卡吗?什么时候到账?
- 下一篇: 微信怎么还信用卡?微信还信用卡常见问题及