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

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


当前回答

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

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

其他回答

在c#中创建本地/托管程序集是可能的,但并不那么容易。如果你使用c++的话,事情就简单多了,因为Visual c++编译器可以像创建其他程序集一样轻松地创建混合程序集。

除非你对生成混合程序集有严格的要求,否则我同意MusiGenesis的观点,这真的不值得用c#来麻烦。如果您需要这样做,也许可以考虑转移到c++ /CLI。

在Visual Studio中右键单击项目,选择项目属性->资源->添加资源->添加现有文件… 并将下面的代码包含到你的App.xaml.cs或等效程序中。

public App()
{
    AppDomain.CurrentDomain.AssemblyResolve +=new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll","");

    dllName = dllName.Replace(".", "_");

    if (dllName.EndsWith("_resources")) return null;

    System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());

    byte[] bytes = (byte[])rm.GetObject(dllName);

    return System.Reflection.Assembly.Load(bytes);
}

以下是我的博客原文: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/

在上面扩展@Bobby的回答。您可以编辑.csproj,以便在构建时使用IL-Repack自动将所有文件打包到单个程序集中。

使用Install- package ILRepack.MSBuild.Task安装nuget ILRepack.MSBuild.Task包 编辑.csproj的AfterBuild部分

下面是一个简单的示例,它将ExampleAssemblyToMerge.dll合并到项目输出中。

<!-- ILRepack -->
<Target Name="AfterBuild" Condition="'$(Configuration)' == 'Release'">

   <ItemGroup>
    <InputAssemblies Include="$(OutputPath)\$(AssemblyName).exe" />
    <InputAssemblies Include="$(OutputPath)\ExampleAssemblyToMerge.dll" />
   </ItemGroup>

   <ILRepack 
    Parallel="true"
    Internalize="true"
    InputAssemblies="@(InputAssemblies)"
    TargetKind="Exe"
    OutputFile="$(OutputPath)\$(AssemblyName).exe"
   />
</Target>

以下方法不使用外部工具,自动包含所有需要的DLL(不需要手动操作,一切都在编译时完成)

我在这里读了很多回答说使用ILMerge, ILRepack或Jeffrey Ritcher方法,但这些方法都不适合WPF应用程序,也不容易使用。

当你有很多DLL时,很难手动将你需要的DLL包含在你的exe中。我发现的最好的方法是由wegger在StackOverflow上解释的

为了清晰起见,Copy将他的答案粘贴在这里(全部归功于weged)


1)添加到你的。csproj文件:

<Target Name="AfterResolveReferences">
  <ItemGroup>
    <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
      <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
    </EmbeddedResource>
  </ItemGroup>
</Target>

2)让你的Main Program.cs看起来像这样:

[STAThreadAttribute]
public static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
    App.Main();
}

3)添加OnResolveAssembly方法:

private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
    Assembly executingAssembly = Assembly.GetExecutingAssembly();
    AssemblyName assemblyName = new AssemblyName(args.Name);

    var path = assemblyName.Name + ".dll";
    if (assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false) path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);

    using (Stream stream = executingAssembly.GetManifestResourceStream(path))
    {
        if (stream == null) return null;

        var assemblyRawBytes = new byte[stream.Length];
        stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
        return Assembly.Load(assemblyRawBytes);
    }
}

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

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