【转】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这个类存储着探索目录的信息,其成员包括:ApplicationBasePrivateBinPath

程序搜索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.LoadAssembly.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/欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/436292.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件

这两天忙着把框架改为支持加载C和Delphi的插件&#xff0c;来不及更新blog了。 原来的写的框架只支持c#插件&#xff0c;这个好做&#xff0c;直接用c#的反射功能便可。但是公司不是所有人都搞C#&#xff0c;也不是所有的程序C#都能很好的完成&#xff0c;又或者其他公司…

【转】一篇易懂的CAN通讯协议指南1

转自&#xff1a;https://zhuanlan.zhihu.com/p/162708070 本文力求以图文并茂来接好CAN通讯协议的基础知识&#xff0c;希望能给有兴趣的朋友带来一些收获。 为了便于大家理解与接受&#xff0c;请先看一幅图&#xff1a; 图1 电话会议 简单地讲CAN总线就如上图1中两根粗黄线…

【转】CAN协议深度解析-简单易懂协议详解

转自&#xff1a;https://zhuanlan.zhihu.com/p/343607068 CAN接口兼容规范2.0A和2.0B(主动)&#xff0c;位速率高达1兆位/秒。它可以接收和发送11位标识符的标准帧&#xff0c;也可以接收和发送29位标识符的扩展帧。 扩展帧的仲裁域有29位&#xff0c;可以出现2^29中报文&…

深度神经网络下的风格迁移模型(C#)

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 这个是C#版本的&#xff0c;这里就只放出代码。VB.Net版本请参看 深度神经网络下的风格迁移模型-CSDN博客 斯坦福大学李飞飞团队的…

使用 Visual Studio 2005 Team System 进行单元测试并生成用于 Unit Test Framework 的源代码...

PS&#xff1a;微软专家写的一往篇VSTS2005测试功能说明&#xff0c;非常详细。适合初学者查看。适用于&#xff1a;Microsoft Visual Studio 2005 Team System Beta 2Team Architect & Team Test EditionsMicrosoft Visual C# 2005摘要&#xff1a; Scott 详细介绍自动化单…

【转】C++ win32窗口创建详解

转自&#xff1a;https://my.oschina.net/u/4328928/blog/3315324 本篇所讲解的内容仅限于 Windows 操作系统且限于 win32程序设计 现在我们在Windows系统上用的软件, 早已不是控制台界面, 而是窗体应用程序 窗体与控制台的区别就是: 有了窗口的概念 由于C的语法复杂, 使得…

2.3 Factory Method(工厂方法)

【返回目录】 我们现在把场景从险象丛生的特工战切换到更为壮观的二战中来&#xff0c;很多人都看过《拯救大兵瑞恩》&#xff0c;这部电影最著名的两场战斗非首和尾莫属&#xff0c;我们就用最后一场战役来举例说明什么是工厂方法吧。 相比诺曼底登陆&#xff0c;最后一场战役…

[转] UML中关联、依赖、聚集等关系的异同

1. 关联&#xff1a;连接模型元素及链接实例&#xff0c;用一条实线来表示&#xff1b;2. 依赖&#xff1a;表示一个元素以某种方式依赖于另一个元素&#xff0c;用一条虚线加箭头来表示&#xff1b;3. 聚集&#xff1a;表示整体与部分的关系&#xff0c;用一条实线加空心菱…

不同职业的面试着装技巧。

美女姜培琳&#xff1a;传授独家心经 不同职业的面试着装技巧。 一般来说&#xff0c;职场中精英女性的装扮&#xff0c;首要应讲求端庄、稳重。人们对服饰过于花哨怪异者的工作能力、工作作风、敬业精神、生活态度等&#xff0c;都会持怀疑的态度。 其实&#x…

【转】C++中的字符串(String)和数值转换

『写在前边』 因为写PAT总是遇到字符串&#xff08;主要是String&#xff09;和数值之间的转化&#xff0c;所以整理一下以便好复习。 『String类型的字符串』 这里数值和字符串相互转换的例子&#xff0c;使用的是stringstream函数&#xff0c;在c11当中有定义好的现成的函数…

好开心

好开心&#xff01;收到我们家lily的礼物&#xff01; 前天&#xff0c;lily传给我一个flash相册&#xff0c;他将我们认识以来的合照做成了flash&#xff0c;配上了音乐。看了好感动&#xff0c;好开心&#xff01; 其实照片倒不是很多&#xff0c;也就7到8张吧&#xff0c;但…

谈谈基于SQL Server 的Exception Handlingp[下篇]

六、SqlException 在上面一节中&#xff0c;我给出了一个完整的例子说明了&#xff1a;如何在将message定义在sys.messages中保证message的一致性和可维护性&#xff1b;如何在Stored procedure中使用RAISERROR将一个可预知的Error抛出&#xff1b;如何在Stored procedure中使用…

【转】修改static控件背景颜色和文字颜色

当 static 控件或具有 ES_READONLY 风格的 edit 控件被绘制时&#xff0c;会向父窗口发送 WM_CTLCOLORSTATIC 消息。如果我们在窗口过程中处理该消息&#xff0c;就必须返回一个画刷句柄&#xff0c;Windows 会使用该画刷来绘制控件背景&#xff08;子窗口背景&#xff09;。 也…

java中随机数彩票练习_基于javascript实现彩票随机数生成(简单版)

本文实例讲解了JavaScript 实现彩票中随机数组的获取详细代码&#xff0c;分享给大家供大家参考&#xff0c;具体内容如下效果图&#xff1a;具体代码&#xff1a;Math.random方法彩票随机数的生成开始获取随机数组//获取节点var btnGo document.getElementById("btnGo&q…

【转】Windows编程之滚动条—滚动条消息

在用鼠标单击滚动条或者拖动卷动方块时&#xff0c;Windows给窗口消息处理程序发送WM_VSCROLL&#xff08;供上下移动&#xff09;和WM_HSCROLL&#xff08;供左右移动&#xff09;消息。在滚动条上的每个鼠标动作都至少产生两个消息&#xff0c;一条在按下鼠标按钮时产生&…

juc是什么java_JUC简介

JUC是什么JUC是 在Java 5.0添加的 java.util.concurrent包的简称&#xff0c;目的就是为了更好的支持高并发任务&#xff0c;让开发者利用这个包进行的多线程编程时可以有效的减少竞争条件和死锁线程。JUC的结构1&#xff0c;tools(工具类)&#xff1a;又叫信号量三组工具类&am…

WinAPI: SetTextColor - 设置设备环境的文本颜色

//声明: SetTextColor(DC: HDC; {设备环境句柄}Color: COLORREF {颜色值} ): COLORREF; {返回指定的颜色值; 如果返回值是 CLR_INVALID 表示设置失败}//举例: procedure TForm1.Button1Click(Sender: TObject); beginSetTextColor(Canvas.Handle, clRed);Canvas.Te…

java volidate线程安全_03.(多线程与并发)面试题-02--Volidate的原理和指令重排序

线程栈(线程的工作内存)保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候&#xff0c;首先通过对象的引用找到对应在堆内存的变量的值&#xff0c;然后把堆内存变量的具体值load到线程本地内存中&#xff0c;建立一个变量副本&#xff0c;之后线程就不再和对象…

选址问题java_学习使用分治算法来解决邮局选址问题(Java实现)

邮局选址问题(分治算法)前言提示&#xff1a;在算法的学习过程中我们会遇到各种各样的算法思想&#xff0c;其中最常见的就有分治算法思想&#xff0c;而本文的问题邮局选址问题就是基于分治思想而去实现的一个日常问题提示&#xff1a;以下是本文内容&#xff0c;我将对该问题…

WinAPI: GetCurrentThread、GetCurrentThreadId、GetCurrentProcess、GetCurrentProcessId

{返回当前线程的虚拟句柄} GetCurrentThread: THandle;{返回当前线程 ID} GetCurrentThreadId: DWORD;{返回当前进程的虚拟句柄} GetCurrentProcess: THandle;{返回当前进程 ID} GetCurrentProcessId: DWORD;提示:ID 是系统唯一的标识.所谓虚拟句柄, 就是该句柄只在调用进程的进…