C#将dll打包到程序中的具体实现
发布时间:2022-11-22 16:39:34
直接进入主题
先来看一个栗子,假设现在有一个第三方dll
namespace TestLibrary1
{
public class Test
{
public void Point()
{
Console.WriteLine("aaabbbccc");
}
}
}
TestLibrary1.dll
在项目中引用,然后调用其中的方法Test,将输出aaabbbccc
using System;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
var test = new TestLibrary1.Test();
test.Point();
Console.ReadLine();
}
}
}
效果
但是很显然,当你把程序发给你的客户的时候必须要携带一个dll,否则就会这样
当程序在运行中,某个程序集加载失败的时候 会触发 AppDomain.CurrentDomain.AssemblyResolve 事件
//
// 摘要:
// 在对程序集的解析失败时发生。
public event ResolveEventHandler AssemblyResolve;
在这个事件中,可以重新为加载失败的程序集手动加载
如果你将dll作为资源文件打包的你的应用程序中(或者类库中)
就可以在硬盘加载失败的时候 从资源文件中加载对应的dll
就像这样:
class Program
{
static Program()
{
//这个绑定事件必须要在引用到TestLibrary1这个程序集的方法之前,注意是方法之前,不是语句之间,就算语句是在方法最后一行,在进入方法的时候就会加载程序集,如果这个时候没有绑定事件,则直接抛出异常,或者程序终止了
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//获取加载失败的程序集的全名
var assName = new AssemblyName(args.Name).FullName;
if (args.Name == "TestLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
{
//读取资源
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ConsoleApplication5.TestLibrary1.dll"))
{
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
return Assembly.Load(bytes);//加载资源文件中的dll,代替加载失败的程序集
}
}
throw new DllNotFoundException(assName);
}
//程序进入方法之前会加载程序集,当程序集加载失败,则会进入CurrentDomain_AssemblyResolve事件
static void Main(string[] args)
{
var test = new TestLibrary1.Test();
test.Point();
Console.ReadLine();
}
}
这样就软件以一个exe单独运行了
以上都是我网上看来了...................
--------------------------------------------------------------------------------
不过如果我有很多dll怎么办,总不至于每一个dll写一个分支吧?
所以我准备写一个通用的资源dll加载类
原理蛮简单的,主要是通过StackTrace类获取调用RegistDLL方法的对象,获取到对方的程序集
然后通过Assembly.GetManifestResourceNames()获取所有资源的名称
判断后缀名".dll"(这一步可以自由发挥),然后加载,以加载的程序集的名称为key保存到一个字典中
并绑定AppDomain.AssemblyResolve事件
在程序集加载失败时,从字典中查询同名程序集,如果有,直接从字典中加载
代码如下:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
namespace blqw
{
/// <summary> 载入资源中的动态链接库(dll)文件
/// </summary>
static class LoadResourceDll
{
static Dictionary<string, Assembly> Dlls = new Dictionary<string, Assembly>();
static Dictionary<string, object> Assemblies = new Dictionary<string, object>();
static Assembly AssemblyResolve(object sender, ResolveEventArgs args)
{
//程序集
Assembly ass;
//获取加载失败的程序集的全名
var assName = new AssemblyName(args.Name).FullName;
//判断Dlls集合中是否有已加载的同名程序集
if (Dlls.TryGetValue(assName, out ass) && ass != null)
{
Dlls[assName] = null;//如果有则置空并返回
return ass;
}
else
{
throw new DllNotFoundException(assName);//否则抛出加载失败的异常
}
}
/// <summary> 注册资源中的dll
/// </summary>
public static void RegistDLL()
{
//获取调用者的程序集
var ass = new StackTrace(0).GetFrame(1).GetMethod().Module.Assembly;
//判断程序集是否已经处理
if (Assemblies.ContainsKey(ass.FullName))
{
return;
}
//程序集加入已处理集合
Assemblies.Add(ass.FullName, null);
//绑定程序集加载失败事件(这里我测试了,就算重复绑也是没关系的)
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
//获取所有资源文件文件名
var res = ass.GetManifestResourceNames();
foreach (var r in res)
{
//如果是dll,则加载
if (r.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
{
try
{
var s = ass.GetManifestResourceStream(r);
var bts = new byte[s.Length];
s.Read(bts, 0, (int)s.Length);
var da = Assembly.Load(bts);
//判断是否已经加载
if (Dlls.ContainsKey(da.FullName))
{
continue;
}
Dlls[da.FullName] = da;
}
catch
{
//加载失败就算了...
}
}
}
}
}
}
LoadResource.Dll
猜你喜欢
- 最近在一本J2EE的书中看到了很不错的对集合框架的说明文章,筛选后发上来和大家共享,集合框架提供管理对象集合的接口和类.它包含接口,类,算法
- 本文实例为大家分享了Java实现猜拳游戏的具体代码,供大家参考,具体内容如下一、问题简介通过控制台方式实现一个人机对战的猜拳游戏,用户通过输
- 前言最近碰到了Mybatis一对多查询的场景,在这里总结对比下常见的两种实现方式。本文以常见的订单表和订单详情表来举例说明;数据库表准备订单
- 好久就想着好好搭建一个ssm框架,自己以后用也方便吧,但是最近的事真的是很多,很多事情都没有去干,有时候自己会怀疑一下人生自己该不该去做程序
- 问题在使用 Abp 框架的后台作业时,当后台作业抛出异常,会导致整个程序崩溃。在 Abp 框架的底层执行后台作业的时候,有 try/catc
- java 中死锁问题的实例详解先看代码在做解释public class DeadLock implements Runnable{ &nbs
- 目录1、Stream API2、ParallelStreams执行原理3、ParallelStreams注意事项前言:并行编程势不可挡,Ja
- Annotation(注解)是JDK1.5及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。注解是以&
- Java synchronized 关键字 可以将一个代码块或一个方法标记为同步代码块。同步代码块是指同一时间只能有一个线程执行的代码,并且
- 工具方法:本文的目的是把json串转成map键值对存储,而且只存储叶节点的数据maven 引用jar包版本:<dependency&g
- 判断某字符串是否为空,为空的标准是str==null或str.length()==01.下面是StringUtils判断是否为空的示例:St
- 首先说说什么叫回调函数?在WINDOWS中,程序员想让系统DLL调用自己编写的一个方法,于是利用DLL当中回调函数(CALLBACK)的接口
- 本篇是基于TornadoFx框架对Tooltip组件进行讲解,使用Kotlin语言,和传统Java使用有所区别,仅供参考介绍鼠标悬浮在某个控
- 一、前言知识补充:Arrays.copyOf函数:public static int[] copyOf(int[] original, in
- java Lock接口java.util.concurrent.locks接口Lockpublic interface Loce
- 一、bean实例化——构造方法(常用)bean本质上就是对象,创建bean使用构造方法完成BookD
- import java.util.Arrays;public class HeapSort { publ
- 现象: 1. 表面现象: 方法中输出的日志, 日志文件中找不到, 也没有任何报错(即@Async标注的方法没有执行, 也没有报错)2. 分析
- OAuth2简介OAuth 是一个开放标准,该标准允许用户让第三方应用访问该用户在某一网站上存储的私密资源(如头像、照片、视频等),而在这个
- 本文实例为大家分享了C# SqlHelper应用技巧,供大家参考,具体内容如下使用App.config配置文件封装连接字符串,方便重复使用-