服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#程序(含多个Dll)合并成一个Exe的简单方法

C#程序(含多个Dll)合并成一个Exe的简单方法

2021-12-13 15:21飘渺公子 C#

这篇文章主要为大家详细介绍了C#程序(含多个Dll)合并成一个Exe的简单方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

开发程序的时候经常会引用一些第三方的dll,然后编译生成的exe文件就不能脱离这些dll独立运行了。

但是,很多时候我们本想开发一款只需要一个exe就能完美运行的小工具。那该怎么办呢?

下文介绍一种超简单的方法,不用写一行代码就可轻松实现。

这里我们需要用到一款名为fody.costura的工具。fody.costura是一个fody框架下的插件,可通过nuget安装到vs工程中。安装之后,就可以将项目所依赖的dll(甚至pdb)文件全部打包到exe文件里。

使用方法

  • 在vs中,通过nuget为目标exe工程安装costura.fody。或者通过nuget控制台用命令行安装:install-package costura.fody -version 1.3.3
  • 重新构建项目。

构建完成后,到项目的输出目录下找到新生成的exe文件,你同时会发现输出目录下仍然存在那些dll。不过不用担心,这个exe已经能够独立运行了。你可以把这些dll全部删除后再运行exe试试。

另外,fody.costura还支持一些进阶的特性,例如:

  • 临时程序集文件:在运行exe前自动,自动将dll从exe中解压到文件夹系统中,再通过常规的方式加载该dll。
  • 合并非托管的dll:fody.costura可以合并非托管的dll,但是不会自动合。如果你的程序涉及非托管dll,那么你需要通过修改fody.costura的配置文件来显示地告诉它你想合并哪些非托管的dll。
  • 预加载dll:fody.costura可以帮助你在程序启动时预先加载某些dll,你甚至可以指定这些dll的加载顺序。

以上这些进阶特性都需要你通过修改fody.costura的配置文件来实现,具体的操作步骤可以参考它的官方文档。

好了,fody.costura的使用方式已经介绍完了。如果你对fody.costura的实现原理感到好奇,可以接着往下看。

合并非托管的dll

C#程序(含多个Dll)合并成一个Exe的简单方法

?
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="utf-8"?>
<weavers>
 <costura>
 <unmanaged32assemblies>
  sqlite.interop
 </unmanaged32assemblies>
 <unmanaged64assemblies>
  sqlite.interop
 </unmanaged64assemblies>
 </costura>
</weavers>

实现原理介绍

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

fody.costura在构建项目时会把exe引用到的dll全部嵌入到exe文件中。当程序在运行的过程中用到其中某个dll的时候(此时由于clr无法找到该dll文件,导致appdomain.assemblyresolve事件被触发)再从exe文件的嵌入资源中提取所需的dll。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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方法就能够立即得到调用了。

以上就是fody.costura实现原理的简单介绍。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

延伸 · 阅读

精彩推荐
  • C#深入理解C#的数组

    深入理解C#的数组

    本篇文章主要介绍了C#的数组,数组是一种数据结构,详细的介绍了数组的声明和访问等,有兴趣的可以了解一下。...

    佳园9492021-12-10
  • C#利用C#实现网络爬虫

    利用C#实现网络爬虫

    这篇文章主要介绍了利用C#实现网络爬虫,完整的介绍了C#实现网络爬虫详细过程,感兴趣的小伙伴们可以参考一下...

    C#教程网11852021-11-16
  • C#三十分钟快速掌握C# 6.0知识点

    三十分钟快速掌握C# 6.0知识点

    这篇文章主要介绍了C# 6.0的相关知识点,文中介绍的非常详细,通过这篇文字可以让大家在三十分钟内快速的掌握C# 6.0,需要的朋友可以参考借鉴,下面来...

    雨夜潇湘8272021-12-28
  • C#如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    这篇文章主要给大家介绍了关于如何使用C#将Tensorflow训练的.pb文件用在生产环境的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴...

    bbird201811792022-03-05
  • C#VS2012 程序打包部署图文详解

    VS2012 程序打包部署图文详解

    VS2012虽然没有集成打包工具,但它为我们提供了下载的端口,需要我们手动安装一个插件InstallShield。网上有很多第三方的打包工具,但为什么偏要使用微软...

    张信秀7712021-12-15
  • C#C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    这篇文章主要介绍了C#设计模式之Strategy策略模式解决007大破密码危机问题,简单描述了策略模式的定义并结合加密解密算法实例分析了C#策略模式的具体使用...

    GhostRider10972022-01-21
  • C#C#微信公众号与订阅号接口开发示例代码

    C#微信公众号与订阅号接口开发示例代码

    这篇文章主要介绍了C#微信公众号与订阅号接口开发示例代码,结合实例形式简单分析了C#针对微信接口的调用与处理技巧,需要的朋友可以参考下...

    smartsmile20127762021-11-25
  • C#SQLite在C#中的安装与操作技巧

    SQLite在C#中的安装与操作技巧

    SQLite,是一款轻型的数据库,用于本地的数据储存。其优点有很多,下面通过本文给大家介绍SQLite在C#中的安装与操作技巧,感兴趣的的朋友参考下吧...

    蓝曈魅11162022-01-20