C#将依赖的dll打包到一个exe的最简单方式

@C#将依赖的dll打包到一个exe的最简单方式

使用Costura.Fody

通过Nuget安装
搜索Costura.Fody,点击右侧的安装

安装完后可在引用目录查看到
Costura为该类的名字
安装完后直接点击生产程序即可。
这里有些异常情况需要注意:例如在程序中有参数或者其他文件需要引用的放置其他文件夹,此时需要将该文件夹拷贝过去才能运行。
如下图,1号是打包好的exe,2是程序运行时用的的参数,3是程序运行后自动生成的文件,如果想要完完全全只有一个exe,需要对程序简化程序,或者想办法把其他文件隐藏,或者直接保存到exe中
在这里插入图片描述
原理分析
1.编译时资源嵌入
编译阶段,Costura.Fody通过修改项目的IL(中间语言)代码,将所有的Dll文件作为资源嵌入到生成的exe文件中:
临时程序集文件:在运行EXE前自动,自动将DLL从EXE中解压到文件夹系统中,再通过常规的方式加载该DLL,它还包含一些进阶的特性,例如:
合并非托管的DLL:Fody.Costura可以合并非托管的DLL,但是不会自动合。如果你的程序涉及非托管DLL,那么你需要通过修改Fody.Costura的配置文件来显示地告诉它你想合并哪些非托管的DLL。
预加载DLL:Fody.Costura可以帮助你在程序启动时预先加载某些DLL,你甚至可以指定这些DLL的加载顺序

当CLR试图加载一个程序集但加载失败时,它会引发AppDomain.AssemblyResolve事件。我们的程序可以监听这个事件,并且在这个事件的处理函数中返回这个CLR试图加载的程序集,从而使程序得以继续正常运行。

Fody.Costura在构建项目时会把EXE引用到的DLL全部嵌入到EXE文件中。当程序在运行的过程中用到其中某个DLL的时候(此时由于CLR无法找到该DLL文件,导致AppDomain.AssemblyResolve事件被触发)再从EXE文件的嵌入资源中提取所需的DLL。

下面这两个函数就是Fody.Costura实现这部分逻辑的代码。

public static void Attach()
        {
            var currentDomain = AppDomain.CurrentDomain;
            currentDomain.AssemblyResolve += (s, e) => ResolveAssembly(e.Name);
        }
public static Assembly ResolveAssembly(string assemblyName)
        {
            if (nullCache.ContainsKey(assemblyName))
            {
                return null;
            }

            var requestedAssemblyName = new AssemblyName(assemblyName);

            var assembly = Common.ReadExistingAssembly(requestedAssemblyName);
            if (assembly != null)
            {
                return assembly;
            }

            Common.Log("Loading assembly '{0}' into the AppDomain", requestedAssemblyName);

            assembly = Common.ReadFromEmbeddedResources(assemblyNames, symbolNames, requestedAssemblyName);
            if (assembly == null)
            {
                nullCache.Add(assemblyName, true);

                // Handles retargeted assemblies like PCL
                if (requestedAssemblyName.Flags == AssemblyNameFlags.Retargetable)
                {
                    assembly = Assembly.Load(requestedAssemblyName);
                }
            }
            return assembly;

可以看到,Attach方法监听了AppDomain.AssemblyResolve事件。当CLR无法成功加载某个程序集时, AssemblyResolve事件处理函数会被执行。AssemblyResolve会尝试通过Common.ReadFromEmbeddedResources方法从已加载的程序集的嵌入资源中获取目标程序集,并返回给CLR。

Attach方法是在什么时候执行的呢?

其实是这样的,对于C#语言来说,CLR隐藏了一个大招——CLR可以在每个模块(每个程序集都含有一个或多个模块)加载之前执行一些初始化的代码。但是很遗憾,C#语言无法控制这部分代码。Fody.Costura则是在内部将IL代码直接注入到EXE程序集内部模块的初始化函数中,而这部分IL代码其实就是执行了Attach方法。这样一来,EXE程序集被加载后,Attach方法就能够立即得到调用了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值