如何理解C# 加载DLL的顺序
来源:互联网 发布:maven java home 编辑:程序博客网 时间:2024/06/05 02:06
原文地址 :http://www.cnblogs.com/chenxizhang/archive/2013/03/14/2959688.html
没有做强名称签名的程序集
对于这种情况,CLR查找和加载程序集的方式如下
- 程序的根目录
- 根目录下面,与被引用程序集同名的子目录
- 根目录下面被明确定义为私有目录的子目录
同时,这种情况下,如果有定义codebase,则codebase的优先级最高,而且如果codebase指定的路径找不到,则直接报告错误,不再查找其他目录
有做强名称签名的程序集
对于这种情况,CLR查找和加载程序集的方式如下
- 全局程序集缓存
- 如果有定义codebase,则以codebase定义为准,如果codebase指定的路径找不到,则直接报告错误
- 程序的根目录
- 根目录下面,与被引用程序集同名的子目录
- 根目录下面被明确定义为私有目录的子目录
我们帮助大家更好地理解以上的说明,我准备用范例来做讲解。
1.准备基本范例
下面的范例演示了一个应用程序(MyApplication),和一个类库(MyLibrary) ,MyApplication是引用了MyLibrary的。
MyLibrary中有一个TestClass类型,提供了一个简单的方法(SayHello)
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MyLibrary{ public class TestClass { public void SayHello() { //这里为了演示方便,显示出来当前加载的程序集完整路径 Console.WriteLine(this.GetType().Assembly.Location); Console.WriteLine("Hello,world"); } }}
在MyApplication中,我们就是简单地创建了这个类型的实例,然后调用方法。
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MyApplication{ class Program { static void Main(string[] args) { var c = new MyLibrary.TestClass(); c.SayHello(); Console.Read(); } }}
默认情况下,如果我们编译整个项目,那么MyLibrary.dll会被自动地复制到MyApplication的根目录,如下图所示
运行MyApplication.exe,我们能看到下面这样的输出
我们可以很清楚地看到,当前加载的MyLibrary.dll是来自于MyApplication的根目录的。
2. 假如我们不想将MyLibrary.dll放在应用程序的根目录
有时候,我们会希望单独存放MyLibrary.dll,那么第一种做法就是,直接在应用程序根目录下面建立一个与程序集同名的子目录,然后将程序集放进去。
我们注意到,根目录下面的MyLibrary.dll 被移动到了MyLibrary目录
然后,我们再次运行MyApplication.exe,能看到下面这样的输出:
3.假如我们有很多程序集,希望统一放在一个目录
第二步的方法虽然不错,但有一个问题,就是如果我们引用的程序集很多的话,就需要在根目录下面建立很多子目录。那么,有没有办法统一地将这些程序集放在一个目录中呢?
我们可以通过如下的方式,定义一个特殊的私有路径(PrivatePath)
<?xml version="1.0" encoding="utf-8" ?><configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="libs"></probing> </assemblyBinding> </runtime></configuration>
同时,我们将MyLibrary.dll 移动到libs这个子目录下面去
然后,我们再次运行MyApplication.exe,能看到下面这样的输出:
这也就是说,对于没有签名的程序集,CLR一般会按照如下的规则查找和加载程序集
- 程序的根目录
- 根目录下面,与被引用程序集同名的子目录
- 根目录下面被明确定义为私有目录的子目录
但是,有一个例外
4. codebase的设置是优先的,而且是排他的
codebase是一个特殊的设置,我们可以在配置文件中明确地指定某个程序集的查找路径,这个规则具有最高的优先级,而且如果你做了设置,CLR就一定会按照你的设置去查找,如果找不到,它就报告失败,而不会继续查找其他路径。
<?xml version="1.0" encoding="utf-8" ?><configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="libs"/> <dependentAssembly> <assemblyIdentity name="MyLibrary" culture="neutral" /> <codeBase version="1.0.0.0" href="CodeBase\MyLibrary.dll" /> </dependentAssembly> </assemblyBinding> </runtime></configuration>
请注意,我们保留了libs目录和Mylibrary目录,而且根目录下面也保留了一个MyLibrary.dll。 实际上,当前我们一共有4个dll. 那么到底会加载哪一个呢?
这种情况下,如果codebase下面找不到MyLibrary.dll 会怎么样呢?
我们发现他是会报告错误的,而不会查找其他目录的程序集。
5.如果有强名称签名会怎么样呢?
对程序集进行强名称签名的好处是,可以将其添加到全局全局程序集缓存中。这样既可以实现程序集的共享,又可以从一定程度上提高性能。
签名后,我们将其添加到全局程序集缓存中去
那么这种情况下,不管我们在应用程序根目录(或者下面的子目录)有没有MyLibrary.dll ,CLR都是尝试先从全局程序集缓存中查找和加载的。
需要注意的是,如果程序集是经过了强名称签名,则在定义codebase的时候,应该注明publicKeyToken
<?xml version="1.0" encoding="utf-8" ?><configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="libs"/> <dependentAssembly> <assemblyIdentity name="MyLibrary" publicKeyToken="4a77fca346941a6c" culture="neutral" /> <codeBase version="1.0.0.0" href="CodeBase\MyLibrary.dll" /> </dependentAssembly> </assemblyBinding> </runtime></configuration>
总结
本文通过实例讲解了CLR在查找和加载程序集的时候所遵循的一些规则,针对有强名称和没有强名称的程序集,这些规则略有不同。本文范例代码可以通过这里下载 http://files.cnblogs.com/chenxizhang/AssemblyMatchDemoSolution.zip
- 如何理解C# 加载DLL的顺序
- dll文件的加载顺序
- [转帖]如何在C#中加载自己编写的DLL
- 关于DLL路径加载顺序的问题
- 关于DLL路径加载顺序的问题
- DLL加载顺序
- C#中DLL的引入顺序问题
- C#种动态加载C++的DLL
- C#中加载dll的问题
- C#中加载dll的问题
- 如何在C#中加载自己编写的动态链接库(DLL)
- 如何在C#中加载自己编写的动态链接库(DLL)
- 如何在C#中加载自己编写的动态链接库(DLL)
- 如何在C#中加载自己编写的动态链接库(DLL)
- c# 如何将下载完的dll文件加载到vs2012中
- C# 无法加载DLL(XXX.DLL):找不到指定的模块
- c#调用c的dll原理理解
- DLL 加载和卸载顺序
- Spring定时任务的写法
- 添加标签的第三方
- 在线生成InterlliJ注册码
- 从信息技术看世界发展
- 中文分词算法总结
- 如何理解C# 加载DLL的顺序
- Linux 上安装JDK(RPM版)
- Genymotion的使用
- Java 正则校验金额,且小数点只能是2位
- 【c++】简单了解并行计算库PPL
- Windows下Nexus 5的Android 5.0以上版本官方ROM的刷机教程
- 利用dnsmap功能解决DNS的缺陷
- android中隐藏软键盘唯一有效的方法
- 库函数优先级队列(priority_queue)