是否可以将一个预先存在的DLL嵌入到一个编译好的c#可执行文件中(这样你就只有一个文件可以分发)?如果这是可能的,人们会怎么去做呢?

通常情况下,我不介意把dll放在外面,让安装程序处理所有事情,但工作中有几个人问过我这个问题,老实说,我不知道。


当前回答

通常,您需要某种形式的后构建工具来执行您所描述的程序集合并。有一个免费的工具叫做Eazfuscator (eazfuscator.blogspot.com/),它是为字节码分解设计的,同时也处理程序集合并。您可以将此添加到Visual Studio的构建后命令行中以合并程序集,但由于在任何重要的程序集合并场景中会出现的问题,您的里程将有所不同。

您还可以检查构建make untitil NANT是否具有在构建后合并程序集的功能,但我自己对NANT不够熟悉,无法确定是否内置了该功能。

还有很多很多Visual Studio插件会在构建应用程序时执行程序集合并。

或者,如果你不需要自动完成,有很多工具,比如ILMerge,可以将。net程序集合并到一个文件中。

我在合并程序集时遇到的最大问题是它们是否使用类似的名称空间。或者更糟的是,引用同一个dll的不同版本(我的问题通常是NUnit dll文件)。

其他回答

杰弗里·里希特的节选非常好。简而言之,将库作为嵌入式资源添加,并在其他任何事情之前添加回调。下面是我放在控制台应用程序Main方法开头的一个版本的代码(在他的页面的评论中找到)(只是要确保任何使用库的调用都是在不同的方法中)。

AppDomain.CurrentDomain.AssemblyResolve += (sender, bargs) =>
        {
            String dllName = new AssemblyName(bargs.Name).Name + ".dll";
            var assem = Assembly.GetExecutingAssembly();
            String resourceName = assem.GetManifestResourceNames().FirstOrDefault(rn => rn.EndsWith(dllName));
            if (resourceName == null) return null; // Not found, maybe another handler will find it
            using (var stream = assem.GetManifestResourceStream(resourceName))
            {
                Byte[] assemblyData = new Byte[stream.Length];
                stream.Read(assemblyData, 0, assemblyData.Length);
                return Assembly.Load(assemblyData);
            }
        };

另一个可以很好地处理这个问题的产品是SmartAssembly,网址是SmartAssembly.com。该产品除了将所有依赖项合并到单个DLL中之外,还(可选地)混淆代码,删除额外的元数据以减少生成的文件大小,并且还可以实际优化IL以提高运行时性能。

它还向您的软件(如果需要的话)添加了某种全局异常处理/报告功能,这可能很有用。我相信它还有一个命令行API,因此您可以将其作为构建过程的一部分。

您可以将dll作为嵌入式资源添加,然后让程序在启动时将它们解压缩到应用程序目录中(在检查它们是否已经存在之后)。

虽然制作安装文件非常容易,但我认为这样做并不值得。

编辑:这种技术对于. net程序集来说很容易。与非。NET dll,这将是更多的工作(你必须弄清楚在哪里解包文件和注册它们等等)。

如果你使用的是。net Core 3.0

你可以使用带有PublishSingleFile属性的dotnet publish命令:

dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true

唯一的缺点是你最终会得到一个巨大的EXE文件。

如果它们实际上是托管程序集,您可以使用ILMerge。对于本地dll,您将有更多的工作要做。

请参见:如何将c++ windows dll合并到c#应用程序exe中?