系列文章

程序目录的整理

想必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);
}

参考文章

C#开发奇技淫巧三:把dll放在不同的目录让你的程序更整洁的更多相关文章

  1. .NET分离exe和dll在不同的目录让你的程序更整洁

    1.引言 在一个项目开发中一般都是把引用的dll放在根目录下,随着项目的日益增大,根目录下的dll文件就会越来越多,合理规划这些dll的存放地址,可以使整个项目更加的规范与美观.这篇文章就为大家介绍关 ...

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

    原文:C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件 这两天忙着把框架改为支持加载C++和Delphi的插件,来不及更新blog了.      原来的写的框架只支持c#插件,这个好做 ...

  3. Lucene.Net 2.3.1开发介绍 —— 三、索引(三)

    原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(三) 3.Field配置所产生的效果 索引数据,简单的代码,只要两个方法就搞定了,而在索引过程中用到的一些类里最简单,作用也不小的就是F ...

  4. Android ROM开发(三)——精简官方ROM并且内置ROOT权限,开启Romer之路

    Android ROM开发(三)--精简官方ROM并且内置ROOT权限,开启Romer之路 相信ROM的相关信息大家通过前几篇的学习都是有所了解了,这里就不在一一提示了,这里我们下载一个官方包,我们还 ...

  5. S5PV210开发系列三_简易Bootloader的实现

    S5PV210开发系列三 简易Bootloader的实现 象棋小子          1048272975 Bootloader是嵌入式系统上电后第一段运行的代码.对于功能简单的处理器,可能并没有Bo ...

  6. HyperLeger Fabric开发(三)——HyperLeger Fabric架构

    HyperLeger Fabric开发(三)--HyperLeger Fabric架构 一.HyperLeger Fabric逻辑架构 1.HyperLeger Fabric逻辑架构简介 Fabric ...

  7. Java开发学习(三十六)----SpringBoot三种配置文件解析

    一. 配置文件格式 我们现在启动服务器默认的端口号是 8080,访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80,这样在访问的时 ...

  8. Java开发学习(三十七)----SpringBoot多环境配置及配置文件分类

    一.多环境配置 在工作中,对于开发环境.测试环境.生产环境的配置肯定都不相同,比如我们开发阶段会在自己的电脑上安装 mysql ,连接自己电脑上的 mysql 即可,但是项目开发完毕后要上线就需要该配 ...

  9. DLL放在指定目录 以及设置dll调用路径

    一.DLL放在指定目录 在编写C# winform程序中,不免一个项目会有多个工程文件,而这些工程文件之间是相互引用的,所以不想将工程的生成结果(exe或者dll)放在当前工程bin目录下的Debug ...

随机推荐

  1. Unity3d学习 预设体(prefab)的一些理解

    之前一直在想如果要在Unity3d上创建很多个具有相同结构的对象,是如何做的,后来查了相关资料发现预设体可以解决这个问题! 预设体的概念: 组件的集合体 , 预制物体可以实例化成游戏对象. 创建预设体 ...

  2. 如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念

    一.前言     DDD(领域驱动设计)的一些介绍网上资料很多,这里就不继续描述了.自己使用领域驱动设计摸滚打爬也有2年多的时间,出于对知识的总结和分享,也是对自我理解的一个公开检验,介于博客园这个平 ...

  3. 本人提供微软系.NET技术顾问服务,欢迎企业咨询!

    背景: 1:目前微软系.NET技术高端人才缺少. 2:企业很难直接招到高端技术人才. 3:本人提供.NET技术顾问,保障你的产品或项目在正确的技术方向. 技术顾问服务 硬服务项: 1:提供技术.决策. ...

  4. iOS热更新-8种实现方式

    一.JSPatch 热更新时,从服务器拉去js脚本.理论上可以修改和新建所有的模块,但是不建议这样做. 建议 用来做紧急的小需求和 修复严重的线上bug. 二.lua脚本 比如: wax.热更新时,从 ...

  5. SQL Server 常用内置函数(built-in)持续整理

    本文用于收集在运维中经常使用的系统内置函数,持续整理中 一,常用Metadata函数 1,查看数据库的ID和Name db_id(‘DB Name’),db_name('DB ID') 2,查看对象的 ...

  6. SQL Server 2014 新特性——内存数据库

    SQL Server 2014 新特性——内存数据库 目录 SQL Server 2014 新特性——内存数据库 简介: 设计目的和原因: 专业名词 In-Memory OLTP不同之处 内存优化表 ...

  7. const extern static 终极指南

    const extern static 终极指南 不管是从事哪种语言的开发工作,const extern static 这三个关键字的用法和原理都是我们必须明白的.本文将对此做出非常详细的讲解. co ...

  8. angularjs 依赖注入--自己学着实现

    在用angular依赖注入时,感觉很好用,他的出现是 为了"削减计算机程序的耦合问题" ,我怀着敬畏与好奇的心情,轻轻的走进了angular源码,看看他到底是怎么实现的,我也想写个 ...

  9. 水平可见直线 bzoj 1007

    水平可见直线 (1s 128M) lines [问题描述] 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆 ...

  10. iOS微信第三方登录实现

    iOS微信第三方登录实现   一.接入微信第三方登录准备工作.移动应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统.在进行微信OAuth2.0授权登录接入之前,在微信开 ...