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

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


当前回答

试试这个:

https://github.com/ytk2128/dll-merger

在这里你可以合并所有32位dll /exe -即使它不是“。net”dll -所以对我来说更好,然后ilmerge为例…

其他回答

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

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

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

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

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

.NET Core 3.0原生支持编译为单个.exe

该特性是通过在项目文件(.csproj)中使用以下属性启用的:

    <PropertyGroup>
        <PublishSingleFile>true</PublishSingleFile>
    </PropertyGroup>

这无需任何外部工具即可完成。

详见我对这个问题的回答。

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

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

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

我使用从.vbs脚本调用的csc.exe编译器。

在xyz.cs脚本中,在指令之后添加以下行(我的例子是用于Renci SSH):

using System;
using Renci;//FOR THE SSH
using System.Net;//FOR THE ADDRESS TRANSLATION
using System.Reflection;//FOR THE Assembly

//+ref>"C:\Program Files (x86)\Microsoft\ILMerge\Renci.SshNet.dll"
//+res>"C:\Program Files (x86)\Microsoft\ILMerge\Renci.SshNet.dll"
//+ico>"C:\Program Files (x86)\Microsoft CAPICOM 2.1.0.2 SDK\Samples\c_sharp\xmldsig\resources\Traffic.ico"

下面的.vbs脚本将提取ref、res和ico标记,以形成csc命令。

然后在Main中添加程序集解析器调用者:

public static void Main(string[] args)
{
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    .

...并在类中添加解析器本身:

    static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        String resourceName = new AssemblyName(args.Name).Name + ".dll";

        using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
        {
            Byte[] assemblyData = new Byte[stream.Length];
            stream.Read(assemblyData, 0, assemblyData.Length);
            return Assembly.Load(assemblyData);
        }

    }

我将vbs脚本命名为匹配.cs文件名(例如ssh。VBS查找ssh.cs);这使得运行脚本更容易很多次,但如果你不是像我这样的白痴,那么一个通用脚本可以从拖放中获取目标.cs文件:

    Dim name_,oShell,fso
    Set oShell = CreateObject("Shell.Application")
    Set fso = CreateObject("Scripting.fileSystemObject")

    'TAKE THE VBS SCRIPT NAME AS THE TARGET FILE NAME
    '################################################
    name_ = Split(wscript.ScriptName, ".")(0)

    'GET THE EXTERNAL DLL's AND ICON NAMES FROM THE .CS FILE
    '#######################################################
    Const OPEN_FILE_FOR_READING = 1
    Set objInputFile = fso.OpenTextFile(name_ & ".cs", 1)

    'READ EVERYTHING INTO AN ARRAY
    '#############################
    inputData = Split(objInputFile.ReadAll, vbNewline)

    For each strData In inputData

        if left(strData,7)="//+ref>" then 
            csc_references = csc_references & " /reference:" &         trim(replace(strData,"//+ref>","")) & " "
        end if

        if left(strData,7)="//+res>" then 
            csc_resources = csc_resources & " /resource:" & trim(replace(strData,"//+res>","")) & " "
        end if

        if left(strData,7)="//+ico>" then 
            csc_icon = " /win32icon:" & trim(replace(strData,"//+ico>","")) & " "
        end if
    Next

    objInputFile.Close


    'COMPILE THE FILE
    '################
    oShell.ShellExecute "c:\windows\microsoft.net\framework\v3.5\csc.exe", "/warn:1 /target:exe " & csc_references & csc_resources & csc_icon & " " & name_ & ".cs", "", "runas", 2


    WScript.Quit(0)

是的,可以将. net可执行文件与库合并。有多种可用的工具来完成这项工作:

ILMerge是一个实用程序,可用于将多个. net程序集合并为单个程序集。 Mono mkbundle,将libmono的exe和所有程序集打包到一个二进制包中。 IL-Repack是ILMerge的FLOSS替代品,具有一些附加特性。

此外,这可以与Mono链接器结合使用,它可以删除未使用的代码,从而使生成的程序集更小。

另一种可能是使用。net z,它不仅允许压缩程序集,还可以将dll直接打包到exe中。与上面提到的解决方案的不同之处在于,.NETZ不会合并它们,它们是单独的程序集,但被打包到一个包中。

. netz是一个开源工具,它压缩和打包Microsoft . net Framework可执行文件(EXE, DLL),以使它们更小。