程序目錄的整理
想必C#的開發(fā)者都遇到過這個問題,引用的dll都放在根目錄下,隨著項目的日益增大,根目錄下充滿了各種各樣的dll,非常的不美觀。
如果能夠把dll按照想要的目錄來存放,那么系統(tǒng)就美觀多了,以下是我常用的程序各文件的分布:
【3rdLibs】
NLog.dll
Newtonsoft.Json.dll
……
【MyLibs】
【Resources】
【Images】
Excecutable.exe
Excecuteble.exe.config
網(wǎng)上有很多的文章述說這個,比如使用Assembly.Load,但是沒有說明在程序中怎么使用,也沒有給出具體的代碼。這里我結(jié)合自己多年的實(shí)踐經(jīng)驗,再把整個流程和方法詳細(xì)敘述一遍,以便各位看官有個具體的體會。
系統(tǒng)搜索dll的目錄以及順序
CLR解析一個程序集會在一個根目錄內(nèi)進(jìn)行搜索,整個探索過程又稱Probing,這個根目錄很顯然就是當(dāng)前包含當(dāng)前程序集的目錄。
AppDomainSetup這個類存儲著探索目錄的信息,其成員包括:ApplicationBase
、PrivateBinPath
。
程序搜索dll的順序如下(區(qū)分強(qiáng)名稱簽名的和沒有強(qiáng)名稱簽名的程序集):
沒有做強(qiáng)名稱簽名的程序集:
具有強(qiáng)名稱簽名的程序集:
全局程序集緩存
如果有定義codebase,則以codebase定義為準(zhǔn),如果codebase指定的路徑找不到,則直接報告錯誤
程序的根目錄
根目錄下面,與被引用程序集同名的子目錄
根目錄下面被明確定義為私有目錄的子目錄
在目錄中查找的時候,如果dll查找不到,則會嘗試查找同名的exe
如果程序集帶有區(qū)域性,而不是語言中立的,則還會嘗試查找以語言區(qū)域命名的子目錄
如何讓程序識別不同目錄下的dll?
我們看到,上面的順序無論是否有強(qiáng)名稱簽名看,都提到了一個名詞“私有目錄”
方法一:配置App.config文件的privatePath
——【推薦】
這是最簡單的方法,當(dāng)然也有一定的局限性,就是沒法對dll做控制,另外,無法解決第三方DllImprt
中引入的程序集不在根目錄下的問題,不過無論怎么說,這個都基本解決了問題。
配置如下,多個目錄用;分隔
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="3rdLib;MyLibs;SubFolder\Sub.dll"/>
</assemblyBinding></runtime>
方法二:訂閱程序集解析事件AssemblyResolve
在代碼中解析
應(yīng)用程序集域中支持在程序集解析時的處理:AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
。通過這個事件,我們可以在程序集解析時,根據(jù)不同的程序集做不用的處理,比如加載x86的程序集還是64位的程序集,當(dāng)然也就可以指定程序集目錄了
這也正是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的代碼之前設(shè)置重置當(dāng)前環(huán)境的目錄
這個方法就是通過Environment.CurrentDirectory=customPath
,這樣,在調(diào)用dll方法時,因為目錄已經(jīng)切換到了
這是一個取巧的方法,不是很實(shí)用,要來回切換程序集目錄,但是在某些情況下非常好用
如何處理[dllImport]
中的程序集的加載
自己寫dllImport
如果是自己寫,那么久好控制了,可以直接指定相對的目錄DllImport(3rdLibs\NLog.dll)
。不過這種方法不一定可靠,在某些系統(tǒng)硬是加載不了,如果使用了dllImport還是,推薦下面的另外一種方法。
引用的C#的插件又使用了dllImport
這是很多文章都沒有提及的:
因為無法更改路徑,那么只能夠使用上述特殊的方法,更改當(dāng)前程序的路徑
當(dāng)然,還有更省事一點(diǎn)的做法,就是在系統(tǒng)環(huán)境中,增加一條記錄,指向要加載的dll的所在目錄。因為C++的代碼中,Windows目錄和Windows\System32目錄以及環(huán)境變量設(shè)定的目錄都是搜索路徑之一。
這里提供怎么從C#中修改系統(tǒng)環(huán)境變量的代碼:
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);
}
參考文章
該文章在 2024/6/6 10:10:37 編輯過