Fody NuGet 包如何在编译过程结束时合并程序集?

How does the Fody NuGet package merge assemblies at the end of the compile process?

最近我遇到了一个用于修改 .NET 程序集的 NuGet 包,特别是有一个 Costura NuGet "plugin" 用于 Fody 包,它在 C# 编译器完成后合并程序集。

我找不到对 .csproj 文件(除了 NuGet 导入)的任何修改,这些修改显示了在构建程序集后执行的任务。

我想知道 Fody 如何能够在构建后 运行 编码而没有任何明显的配置更改。

Fody 将 this .targets 文件添加到您的项目中。如果你有一个经典的 NET 框架项目,你会看到它已添加到 .csproj 文件中。如果您有一个 netstandard 项目(新项目格式),它会在构建期间直接从 nuget 包中自动获取,因此您不会在项目中看到它(但您会在 \obj\ 文件夹中看到它,稍微重命名) .

简化:该目标在“AfterCompile”目标之后执行。它搜索 Weavers.xml 文件。对于它在列表中找到的每个编织器(例如 Costura),它调用编织器的程序集。编织者使用基于 Mono/Cecil 的 Fody 基础架构来处理您的程序集的 IL,post 构建并重写 IL。

在 Costura 的情况下(再次简化),它将每个参考程序集变成一个嵌入式资源。然后它会向您的程序集添加一个 Module Initializer。在程序集中的任何代码被调用之前,模块初始化器(在 C#9 之前你不能用纯 C# 编写的东西)保证 运行——把它想象成一个静态构造函数,但对于程序集。

它添加到模块初始值设定项的代码附加了一个 AssemblyResolveEvent to the AppDomain. This handler will use a manifest resource stream 以满足 Costura 通过使用流中的字节调用 Assembly.Load 嵌入的程序集的分辨率。然后它 returns 来自处理程序的 Assembly 对象,从而满足程序集的决议。或者,Costura 可以将 DLL 提取到磁盘上的临时位置,然后使用该路径来满足解析(有时需要,具体取决于所涉及的 DLL)。

Fody and Costura 文档详细解释了它的工作原理。