ILMerge 确实合并程序集,这很好,但有时不是您想要的。例如,当所讨论的程序集是一个强名称程序集,而您没有它的密钥时,您将无法在不破坏该签名的情况下执行 ILMerge。这意味着您必须部署多个程序集。
作为 ilmerge 的替代方法,您可以将一个或多个程序集作为资源嵌入到您的 exe 或 DLL 中。然后,在运行时,当程序集被加载时,您可以以编程方式提取嵌入式程序集,然后加载并运行它。这听起来很棘手,但只有一点样板代码。
为此,请嵌入程序集,就像嵌入任何其他资源(图像、翻译文件、数据等)一样。然后,设置一个在运行时调用的 AssemblyResolver。它应该在启动类的静态构造函数中设置。代码非常简单。
static NameOfStartupClassHere()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
}
static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
{
Assembly a1 = Assembly.GetExecutingAssembly();
Stream s = a1.GetManifestResourceStream(args.Name);
byte[] block = new byte[s.Length];
s.Read(block, 0, block.Length);
Assembly a2 = Assembly.Load(block);
return a2;
}
ResolveEventArgs 参数的 Name 属性是要解析的程序集的名称。此名称指的是资源,而不是文件名。如果嵌入名为“MyAssembly.dll”的文件,并调用嵌入的资源“Foo”,那么这里需要的名称是“Foo”。但这会令人困惑,所以我建议使用程序集的文件名作为资源的名称。如果您已正确嵌入并命名程序集,则只需使用程序集名称调用 GetManifestResourceStream() 并以这种方式加载程序集。非常简单。
这适用于多个程序集,就像使用单个嵌入式程序集一样好。
在一个真实的应用程序中,您会希望在该例程中进行更好的错误处理 - 比如如果没有给定名称的流怎么办?如果读取失败会发生什么?等等,但这留给你做。
在其余的应用程序代码中,您照常使用程序集中的类型。
构建应用程序时,您需要像往常一样添加对相关程序集的引用。如果使用命令行工具,请使用 csc.exe 中的 /r 选项;如果您使用 Visual Studio,则需要在项目的弹出菜单中添加“添加引用...”。
在运行时,程序集版本检查和验证照常工作。
唯一的区别是分布。当您部署或分发您的应用程序时,您不需要分发嵌入(和引用)程序集的 DLL。只需部署主程序集;无需分发其他程序集,因为它们已嵌入到主 DLL 或 EXE 中。