最近比较懒,加上内容也不多就懒得排版了,字放大了,看起来应该方便一点

直接进入主题

先来看一个栗子,假设现在有一个第三方dll

  1. namespace TestLibrary1
  2. {
  3. public class Test
  4. {
  5. public void Point()
  6. {
  7. Console.WriteLine("aaabbbccc");
  8. }
  9. }
  10. }

TestLibrary1.dll

在项目中引用,然后调用其中的方法Test,将输出aaabbbccc

  1. using System;
  2.  
  3. namespace ConsoleApplication5
  4. {
  5. class Program
  6. {
  7. static void Main(string[] args)
  8. {
  9. var test = new TestLibrary1.Test();
  10. test.Point();
  11. Console.ReadLine();
  12. }
  13. }
  14. }

效果

但是很显然,当你把程序发给你的客户的时候必须要携带一个dll,否则就会这样

  1. 当程序在运行中,某个程序集加载失败的时候 会触发 AppDomain.CurrentDomain.AssemblyResolve 事件
  1. //
  2. // 摘要:
  3. // 在对程序集的解析失败时发生。
  4. public event ResolveEventHandler AssemblyResolve;

在这个事件中,可以重新为加载失败的程序集手动加载

如果你将dll作为资源文件打包的你的应用程序中(或者类库中)

就可以在硬盘加载失败的时候 从资源文件中加载对应的dll

就像这样:

  1. class Program
  2. {
  3. static Program()
  4. {
    //这个绑定事件必须要在引用到TestLibrary1这个程序集的方法之前,注意是方法之前,不是语句之间,就算语句是在方法最后一行,在进入方法的时候就会加载程序集,如果这个时候没有绑定事件,则直接抛出异常,或者程序终止了
  5. AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
  6. }
  7.  
  8. static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
  9. {
  10. //获取加载失败的程序集的全名
  11. var assName = new AssemblyName(args.Name).FullName;
  12. if (args.Name == "TestLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
  13. {
  14. //读取资源
  15. using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ConsoleApplication5.TestLibrary1.dll"))
  16. {
  17. var bytes = new byte[stream.Length];
  18. stream.Read(bytes, , (int)stream.Length);
  19. return Assembly.Load(bytes);//加载资源文件中的dll,代替加载失败的程序集
  20. }
  21. }
  22. throw new DllNotFoundException(assName);
  23. }
  24. //程序进入方法之前会加载程序集,当程序集加载失败,则会进入CurrentDomain_AssemblyResolve事件
  25. static void Main(string[] args)
  26. {
  27. var test = new TestLibrary1.Test();
  28. test.Point();
  29. Console.ReadLine();
  30. }
  31. }

这样就软件以一个exe单独运行了

以上都是我网上看来了...................


不过如果我有很多dll怎么办,总不至于每一个dll写一个分支吧?

所以我准备写一个通用的资源dll加载类

原理蛮简单的,主要是通过StackTrace类获取调用RegistDLL方法的对象,获取到对方的程序集

然后通过Assembly.GetManifestResourceNames()获取所有资源的名称

判断后缀名".dll"(这一步可以自由发挥),然后加载,以加载的程序集的名称为key保存到一个字典中

并绑定AppDomain.AssemblyResolve事件

在程序集加载失败时,从字典中查询同名程序集,如果有,直接从字典中加载

代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Reflection;
  5.  
  6. namespace blqw
  7. {
  8. /// <summary> 载入资源中的动态链接库(dll)文件
  9. /// </summary>
  10. static class LoadResourceDll
  11. {
  12. static Dictionary<string, Assembly> Dlls = new Dictionary<string, Assembly>();
  13. static Dictionary<string, object> Assemblies = new Dictionary<string, object>();
  14.  
  15. static Assembly AssemblyResolve(object sender, ResolveEventArgs args)
  16. {
  17. //程序集
  18. Assembly ass;
  19. //获取加载失败的程序集的全名
  20. var assName = new AssemblyName(args.Name).FullName;
  21. //判断Dlls集合中是否有已加载的同名程序集
  22. if (Dlls.TryGetValue(assName, out ass) && ass != null)
  23. {
  24. Dlls[assName] = null;//如果有则置空并返回
  25. return ass;
  26. }
  27. else
  28. {
  29. throw new DllNotFoundException(assName);//否则抛出加载失败的异常
  30. }
  31. }
  32.  
  33. /// <summary> 注册资源中的dll
  34. /// </summary>
  35. public static void RegistDLL()
  36. {
  37. //获取调用者的程序集
  38. var ass = new StackTrace().GetFrame().GetMethod().Module.Assembly;
  39. //判断程序集是否已经处理
  40. if (Assemblies.ContainsKey(ass.FullName))
  41. {
  42. return;
  43. }
  44. //程序集加入已处理集合
  45. Assemblies.Add(ass.FullName, null);
  46. //绑定程序集加载失败事件(这里我测试了,就算重复绑也是没关系的)
  47. AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
  48. //获取所有资源文件文件名
  49. var res = ass.GetManifestResourceNames();
  50. foreach (var r in res)
  51. {
  52. //如果是dll,则加载
  53. if (r.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
  54. {
  55. try
  56. {
  57. var s = ass.GetManifestResourceStream(r);
  58. var bts = new byte[s.Length];
  59. s.Read(bts, , (int)s.Length);
  60. var da = Assembly.Load(bts);
  61. //判断是否已经加载
  62. if (Dlls.ContainsKey(da.FullName))
  63. {
  64. continue;
  65. }
  66. Dlls[da.FullName] = da;
  67. }
  68. catch
  69. {
  70. //加载失败就算了...
  71. }
  72. }
  73. }
  74. }
  75. }
  76. }

LoadResourceDll

代码下载

C#将dll打包到程序中的更多相关文章

  1. C# 将dll打包到程序中

    本文告诉大家如何把 dll 打包到程序中.很多时候的 软件 在运行的时候需要包括很多 dll 或其他的文件,这样的软件在给其他小伙伴,就需要做一个压缩包,或者用安装软件.这样感觉不太好,所以本文告诉大 ...

  2. 2018-4-29-C#-将dll打包到程序中

    title author date CreateTime categories C# 将dll打包到程序中 lindexi 2018-04-29 09:43:22 +0800 2018-2-13 17 ...

  3. vs 如何将dll打包到exe中

    方法如下:首先需要安装NuGet 然后安装Fody.Costura 重新启动vs 编译项目即可 虽然根目录下还生成了dll但是你的程序已经可以脱离dll运行了,其实是将你的dll打入了exe中你可以看 ...

  4. 使用Microsoft.ExceptionMessageBox.dll捕获WinForm程序中异常信息并弹窗显示

    WinForm程序开发中,在开发模式下对于异常的处理一般都是通过调试的方式来查找异常发生的未知与原因. 下面以“除数为0”的情况来具体说明. Button按钮事件如下: private void bu ...

  5. windows系统下,在C#程序中自动安装字体

    在Windows系统中,原有自带的字体样式有限,有时候我们的程序会使用到个别稀有或系统不自带的字体.因此我们需要将字体打包到程序中,当程序启动时,检测系统是否有该字体,如果没有则安装该字体,也可以动态 ...

  6. 在打包程序中自动安装SQL Server数据库 .

    原文:在打包程序中自动安装SQL Server数据库 . 1.创建安装项目“Setup1”安装项目 在“文件”菜单上指向“添加项目”,然后选择“新建项目”. 在“添加新项目”对话框中,选择“项目类型” ...

  7. 将Winform程序及dll打包成可执行的exe

    使用场景 通常开发的Winform程序,引用了其他类库后,在输出目录下都会产生很多DLL文件,exe执行时必须依赖这些DLL.想要Winform程序只有一个可执行exe文件,又不想打包成安装包,就可以 ...

  8. Winform程序及dll打包成一个可执行的exe

    使用场景 通常开发的Winform程序,引用了其他类库后,在输出目录下都会产生很多DLL文件,exe执行时必须依赖这些DLL.想要Winform程序只有一个可执行exe文件,又不想打包成安装包,就可以 ...

  9. 在程序中使用geos.dll

    1 在项目->property->configuration properties->c/c++->general->additional include directo ...

随机推荐

  1. appcan切换帐号无法提交SVN

     C:\Documents and Settings\Administrator\Application Data\Subversion\auth\svn.simple 

  2. Hadoop2.6.0子项目hadoop-mapreduce-examples的简单介绍

    引文 学习Hadoop的同学们,一定知道如果运行Hadoop自带的各种例子,以大名鼎鼎的wordcount为例,你会输入以下命令: hadoop org.apache.hadoop.examples. ...

  3. Sublime Text 安装Emmet

    1.简单的安装方法 从菜单 View - Show Console 或者 ctrl + ~ 快捷键,调出 console.将以下 Python 代码粘贴进去并 enter 执行,不出意外即完成安装.以 ...

  4. Unity加载模块深度解析(网格篇)

    在上一篇 加载模块深度解析(一)中,我们重点讨论了纹理资源的加载性能.这次,我们再来为你揭开其他主流资源的加载效率. 这是侑虎科技第53篇原创文章,欢迎转发分享,未经作者授权请勿转载.同时如果您有任何 ...

  5. angular中ng-include失效的原因

    使得angular的ng-include指令失效的原因有两个: 例如:在demo.html中的代码<div ng-include = "'demo1.html'">&l ...

  6. SQLServer数据库中创建临时表

    IF object_id('tempdb..#jimmy') is not NULL BEGIN DROP TABLE #jimmy; END IF object_id('tempdb..#jimmy ...

  7. 升级react 15.4,常见的错误及解决方案

    最近项目由react0.14.X升级到react 15版本,因为react15还是做了一些相对大一点的更新的(详情可以参考一下我的另一篇文章关于react15的一点总结),相对:来说react升级之后 ...

  8. 批量创建SQL Server分区文件

    ) declare @i int set @table = 'v3_yqsd_report' begin exec('alter database '+@table+' add filegroup O ...

  9. C++ 文章列表

    C++ 文章列表 Cocos2dx(1) iconv 跨平台的使用方法(Android, IOS) --- 转码(中文乱码)http://www.cnblogs.com/TS-qrt/articles ...

  10. 阿里云安装JDK1.7

    本人阿里云选择的是CentOS 7.0系统,本系列文件将全部基于此环境. 1.下载JDK,版本为jdk-7u79-linux-x64.tar.gz   2.使用FileZilla上传至/softwar ...