C# 程序引用不同路径的DLL文件最详细教程
CSDN 2024-07-06 14:05:01 阅读 77
前言
最近我准备发布软件,但是点开软件目录的一瞬间感觉有点傻眼,整个目录的dll文件,让人看着一塌糊涂,反正我看着就要吐了。
相信做.net应用程序开发的伙伴都有这种感觉,因为项目的需求或者某个功能的需求,需要引用外部的dll文件,随着时间的累积,程序目录下面的dll文件越来越多,而且是各种各样的,最终自己都看不下去了,那么我们有没有什么办法把dll按照文件夹分类存放呢?不用着急,请花10分钟耐心读完本文,一定会解决你的问题的。
Dll引用分类
1.正式教学之前,咱们得先创建一个测试工程(控制台,类库,Winform都行),名字就叫做"Dll路径配置",这里我创建的是一个Winform程序,如下图:
(测试工程项目文件我会放在文章最后)
2.首先准备好我们需要引入的dll文件,这里博主简单的准备了一个测试所用的dll:FileCopy.dll,如下图:
3.接着打开我们的测试工程的编译目录(Debug目录),这里假设我们需要把FileCopy.dll放在"依赖项"这个文件夹下,我们首先创建一个名为“依赖项”的文件夹,如下图:
4.接着将FileCopy.dll复制到“依赖项”文件夹下,如下图:
5.在项目里添加对“FileCopy.dll"的引用,如下图:
6.在引用里修改”FileCopy"的属性,将“复制本地”改为“False”(这个一定要记着)
7.给咱们的主窗口添加一个按钮,如下图:
8.在按钮的事件内调用FileCopy内的函数,如下图:
(如果您创建的不是Winfrom程序,可自定义函数调用FileCopy内的函数,为什么一定要调用呢?其实是这样的,程序在加载dll的时候只会加载正在运行的代码块所调用的dll,如果不调用dll内的功能,程序是不会将dll加载到内存中的)
9.启动程序,运行刚才的代码块(本例中直接点击按钮)
10.接着报错啦!!!!
PS:这里为什么会报错呢?下面我解释一下(这里要认真看,理解为什么报错)
我们知道,.net程序在生成的时候,我们引用的dll文件都会自动复制到我们程序的编译目录下面(默认的是Debug目录下面),所以程序运行的时候也会默认在程序运行目录(Debug目录)下面去查找所依赖的dll文件,本例中咱们依赖的是“FileCopy.dll”,但是"FileCopy.dll“并不在Debug目录下面(因为第6步的时候咱们已经把FileCopy.dll的属性>是否复制本地改为了False,所以生成的时候是不会复制到Debug目录下的),而是在文件夹“依赖项"下面,如图:
所以,直接改dll文件夹添加引用这种方式行不通。
怎么实现引用指定位置的DLL文件
关于如何简化程序dll目录的方法,网上有很多文章,比如:修改Config文件,修改环境变量,这里咱们都不赘述,直接讲我实现的方法:
直接订阅程序集解析事件 AppDomain.CurrentDomain.AssemblyResolve 事件
这个事件在这里可以简单的理解为,主程序在调用程序目录下的dll失败时所要做的事情,需要值得注意的是:这个事件必须在主程序使用dll内的函数之前订阅才有效,通常这个事件订阅放在程序入口(网上也有这个方法,但是一般不会告诉你这点,这点很重要)
在AssemblyResolve事件内,使用Assembly.LoadFrom()方法加载正确的dll路径
1.首先回到咱们的测试工程,在测试工程主窗体下新建下面方法:
<code> /// <summary>
/// 对外解析dll失败时调用
/// </summary>
/// <param name="sender"></param>code>
/// <param name="args"></param>code>
/// <returns></returns>
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string dllName = args.Name.Split(',')[0];//获取主程序正在调用的dll名称
string ExcutePath = Path.GetDirectoryName(Application.ExecutablePath);//获取程序执行的目录
string dllFile = ExcutePath + "\\依赖项\\" + dllName + ".dll";//获取dll路径
return System.Reflection.Assembly.LoadFrom(dllFile);
}
2.接着在窗体初始化处订阅事件,订阅事件的代码如下:
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;//在程序调用dll前绑定这个事件(一般选在程序入口)
3.窗口整体代码如图所示:
4.这个时候再运行程序,点击按钮
5.这时候我们发现,程序没有报错了,并且按照咱们的代码正常运行了,再来看看咱们的程序目录:
这次程序生成目录下同样的没有"FileCopy.dll”文件,不过程序却能正常运行了,证明咱们成功了,不过这样就完了吗?答案是:这样确实就完了!,就这么简单!
应用进阶
咱们已经实现了如何让程序引用指定路径的dll文件,但是实际开发过程中,咱么可能会有很多dll文件,那么上面的代码明显不满足需求了,总不能把所有的dll文件都放在同一个路径下面吧?
要是有多个文件夹呢?下面咱们以上面代码为基础,将其做一个升级,让其支持多个目录。
实现思路如下:
1.首先咱们新建一个工具类类,命名为:SysRef,并在类实例化的时候订阅AppDomain.CurrentDomain.AssemblyResolve事件
2.创建列表用来记录不同的路径
3.在事件响应的时候到每个路径下寻找dll,如果存在dll文件则进行加载
代码如下:
<code> /// <summary>
/// 该类放在程序入口
/// </summary>
public class SysRef
{
/// <summary>
/// Dll文件目录
/// </summary>
private List<string> RefPath { get; set; }
/// <summary>
/// 实例化
/// </summary>
public SysRef()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;//在程序调用dll前绑定这个事件(一般选在程序入口)
RefPath = new List<string>();
}
/// <summary>
/// 设置dll路径
/// </summary>
/// <param name="Path">这个参数是dll所在的文件夹路径,并不是dll本身的路径</param>code>
public void SetRefPath(string Path)
{
if (!Directory.Exists(Path)) return;
if (!RefPath.Contains(Path)) RefPath.Add(Path);
}
/// <summary>
/// 对外解析dll失败时调用
/// </summary>
/// <param name="sender"></param>code>
/// <param name="args"></param>code>
/// <returns></returns>
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string dllName = args.Name.Split(',')[0];//dll程序集名称
//遍历每个路径查找dll
foreach (var item in RefPath)
{
string dllFile = item + "\\" + dllName + ".dll";
//如果路径存在则直接引用dll程序集
if (File.Exists(dllFile))
{
return System.Reflection.Assembly.LoadFrom(dllFile);
}
}
throw new Exception(string.Format("未找到程序:{0}", dllName));
}
}
4.有了工具类以后,使用起来更方便了,再次回到咱们的测试工程,删除之前的事件响应代码和事件订阅代码,在窗口实例化处添加下面代码:
//获取dll文件所在的文件夹
string dllPath = Path.GetDirectoryName(Application.ExecutablePath) + "\\依赖项";
//新建管理类
SysRef sysRef = new SysRef();
sysRef.SetRefPath(dllPath);//注册地址(有多个文件夹地址的时候可以多次调用该方法注册)
5.启动程序并测试效果
6.程序同样正常运行,再看看主程序目录,依旧没有我们引用的dll,但是程序正常运行
PS:再次强调!工具类SysRef必须在主程序使用dll内的函数之前实例化才有效,最好是将SysRef实例化放在程序入口处。实际使用过程中需要根据项目需求修改工具类的代码。今天的教学就到这里了,测试工程项目文件我放在了最后,需要的自取。
测试工程项目文件
百度云盘地址:百度网盘 请输入提取码
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。