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实例化放在程序入口处。实际使用过程中需要根据项目需求修改工具类的代码。今天的教学就到这里了,测试工程项目文件我放在了最后,需要的自取。

测试工程项目文件

百度云盘地址:百度网盘 请输入提取码



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。