C# 在另一个程序集中嵌入程序集

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/222655/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 18:48:21  来源:igfitidea点击:

Embedding assemblies inside another assembly

c#.netdllassemblies

提问by xyz

If you create a class library that uses things from other assemblies, is it possible to embed those other assemblies inside the class library as some kind of resource?

如果您创建一个使用来自其他程序集的内容的类库,是否可以将这些其他程序集作为某种资源嵌入到类库中?

I.e. instead of having MyAssembly.dll, SomeAssembly1.dlland SomeAssembly2.dllsitting on the file system, those other two files get bundled in to MyAssembly.dlland are usable in its code.

即,不是将MyAssembly.dllSomeAssembly1.dllSomeAssembly2.dll放在文件系统上,而是将另外两个文件捆绑到MyAssembly.dll 中并在其代码中可用。



I'm also a little confused about why .NET assemblies are .dllfiles. Didn't this format exist before .NET? Are all .NET assemblies DLLs, but not all DLLs are .NET assemblies? Why do they use the same file format and/or file extension?

我也有点困惑为什么 .NET 程序集是.dll文件。.NET 之前不存在这种格式吗?是否所有 .NET 程序集都是 DLL,但并非所有 DLL 都是 .NET 程序集?为什么他们使用相同的文件格式和/或文件扩展名?

采纳答案by AtliB

Take a look at ILMergefor merging assemblies.

查看用于合并程序集的ILMerge

I'm also a little confused about why .NET assemblies are .dll files. Didn't this format exist before .NET?

我也有点困惑为什么 .NET 程序集是 .dll 文件。.NET 之前不存在这种格式吗?

Yes.

是的。

Are all .NET assemblies DLLs,

都是 .NET 程序集 DLL,

Either DLLs or EXE normally - but can also be netmodule.

通常是 DLL 或 EXE - 但也可以是 netmodule。

but not all DLLs are .NET assemblies?

但不是所有的 DLL 都是 .NET 程序集?

Correct.

正确的。

Why do they use the same file format and/or file extension?

为什么他们使用相同的文件格式和/或文件扩展名?

Why should it be any different - it serves the same purpose!

为什么它会有所不同 - 它用于相同的目的!

回答by Mark Cidade

You canembed an assembly (or any file, actually) as a resource (and then use the ResourceManagerclass to access them), but if you just want to combine assemblies, you're better off using a tool like ILMerge.

可以将程序集(或任何文件,实际上)作为资源嵌入(然后使用ResourceManager类来访问它们),但如果您只想组合程序集,最好使用ILMerge 之类的工具。

EXE and DLL files are Windows portable executables, which are generic enough to accomodate future types of code, including any .NET code (they can also run in DOS but only display a message saying that they're not supposed to run in DOS). They include instructions to fire up the .NET runtime if it isn't already running. It's also possible for a single assembly to span across multiple files, though this is hardly ever the case.

EXE 和 DLL 文件是Windows 可移植的可执行文件,它们的通用性足以容纳未来类型的代码,包括任何 .NET 代码(它们也可以在 DOS 中运行,但只显示一条消息,说明它们不应该在 DOS 中运行)。如果 .NET 运行时尚未运行,它们包括启动 .NET 运行时的说明。单个程序集也可能跨越多个文件,尽管这种情况几乎从未发生过。

回答by hova

There's also the mkbundle utility offered by the Mono project

Mono 项目还提供了 mkbundle 实用程序

回答by Cheeso

ILMerge does merge assemblies, which is nice, but sometimes not quite what you want. For example, when the assembly in question is a strongly-named assembly, and you don't have the key for it, then you cannot do ILMerge without breaking that signature. Which means you have to deploy multiple assemblies.

ILMerge 会合并程序集,这很好,但有时并不是您想要的。例如,如果有问题的程序集是强命名程序集,而您没有它的密钥,那么您不能在不破坏该签名的情况下执行 ILMerge。这意味着您必须部署多个程序集。

As an alternative to ilmerge, you can embed one or more assemblies as resources into your exe or DLL. Then, at runtime, when the assemblies are being loaded, you can extract the embedded assembly programmatically, and load and run it. It sounds tricky but there's just a little bit of boilerplate code.

作为 ilmerge 的替代方法,您可以将一个或多个程序集作为资源嵌入到您的 exe 或 DLL 中。然后,在运行时,当加载程序集时,您可以以编程方式提取嵌入的程序集,然后加载并运行它。这听起来很棘手,但只有一点样板代码。

To do it, embed an assembly, just as you would embed any other resource (image, translation file, data, etc). Then, set up an AssemblyResolver that gets called at runtime. It should be set up in the static constructor of the startup class. The code is very simple.

为此,请嵌入程序集,就像嵌入任何其他资源(图像、翻译文件、数据等)一样。然后,设置一个在运行时调用的 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;
    }

The Name property on the ResolveEventArgs parameter is the name of the assembly to be resolved. This name refers to the resource, not to the filename. If you embed the file named "MyAssembly.dll", and call the embedded resource "Foo", then the name you want here is "Foo". But that would be confusing, so I suggest using the filename of the assembly for the name of the resource. If you have embedded and named your assembly properly, you can just call GetManifestResourceStream() with the assembly name and load the assembly that way. Very simple.

ResolveEventArgs 参数上的 Name 属性是要解析的程序集的名称。此名称指的是资源,而不是文件名。如果您嵌入名为“MyAssembly.dll”的文件,并将嵌入的资源称为“Foo”,那么这里您想要的名称是“Foo”。但这会令人困惑,所以我建议使用程序集的文件名作为资源的名称。如果您已正确嵌入和命名程序集,则只需使用程序集名称调用 GetManifestResourceStream() 并以这种方式加载程序集。很简单。

This works with multiple assemblies, just as nicely as with a single embedded assembly.

这适用于多个程序集,就像使用单个嵌入式程序集一样。

In a real app you're gonna want better error handling in that routine - like what if there is no stream by the given name? What happens if the Read fails? etc. But that's left for you to do.

在真正的应用程序中,您会希望在该例程中进行更好的错误处理 - 就像如果没有给定名称的流怎么办?如果读取失败会发生什么?等等。但那是留给你做的。

In the rest of the application code, you use types from the assembly as normal.

在其余的应用程序代码中,您可以照常使用程序集中的类型。

When you build the app, you need to add a reference to the assembly in question, as you would normally. If you use the command-line tools, use the /r option in csc.exe; if you use Visual Studio, you'll need to "Add Reference..." in the popup menu on the project.

构建应用程序时,您需要像往常一样添加对相关程序集的引用。如果您使用命令行工具,请使用 csc.exe 中的 /r 选项;如果您使用 Visual Studio,则需要在项目的弹出菜单中“添加引用...”。

At runtime, assembly version-checking and verification works as usual.

在运行时,程序集版本检查和验证照常工作。

The only difference is in distribution. When you deploy or distribute your app, you need not distribute the DLL for the embedded (and referenced) assembly. Just deploy the main assembly; there's no need to distribute the other assemblies because they're embedded into the main DLL or EXE.

唯一的区别在于分配。部署或分发应用程序时,无需分发嵌入(和引用)程序集的 DLL。只需部署主程序集;无需分发其他程序集,因为它们已嵌入到主 DLL 或 EXE 中。

回答by Richard Dingwall

Note ILMerge doesn't work with embedded resources like XAML, so WPF apps etc will need to use Cheeso's method.

注意 ILMerge 不适用于 XAML 等嵌入式资源,因此 WPF 应用程序等将需要使用 Cheeso 的方法。

回答by Eric

Why do they use the same file format and/or file extension?

为什么他们使用相同的文件格式和/或文件扩展名?

Why should it be any different - it serves the same purpose!

为什么它会有所不同 - 它用于相同的目的!

My 2¢ bit of clarification here: DLL is Dynamic Link Library. Both the old style .dll (C-code) and .net style .dll are by definition "dynamic link" libraries. So .dll is a proper description for both.

我在这里澄清的 2¢ 位:DLL 是动态链接库。旧式 .dll(C 代码)和 .net 式 .dll 根据定义都是“动态链接”库。所以 .dll 是两者的正确描述。

回答by user3447701

With respect to Cheeso's answer of embedding the assemblies as resources and loading them dynamically using the Load(byte[]) overload using an AssemblyResolve event handler, you need to modify the resolver to check the AppDomain for an existing instance of the Assembly to load and return the existing assembly instance if it's already loaded.

关于 Cheeso 将程序集作为资源嵌入并使用 Load(byte[]) 重载使用 AssemblyResolve 事件处理程序动态加载它们的答案,您需要修改解析器以检查 AppDomain 以获取要加载和如果已经加载,则返回现有的程序集实例。

Assemblies loaded using that overload do not have a context, which can cause the framework to try and reload the assembly multiple times. Without returning an already loaded instance, you can end up with multiple instances of the same assembly code and types that should be equal but won't be, because the framework considers them to be from two different assemblies.

使用该重载加载的程序集没有上下文,这可能导致框架多次尝试重新加载程序集。如果不返回已加载的实例,您最终可能会得到相同汇编代码和类型的多个实例,这些实例应该相等但不会相等,因为框架认为它们来自两个不同的程序集。

At least one way that multiple AssemblyResolve events will be made for the same assembly loaded into the "No context" is when you have references to types it exposes from multiple assemblies loaded into your AppDomain, as code executes that needs those types resolved.

为加载到“无上下文”中的同一个程序集创建多个 AssemblyResolve 事件的至少一种方法是,当您引用它从加载到 AppDomain 的多个程序集中公开的类型时,因为代码执行需要解析这些类型。

https://msdn.microsoft.com/en-us/library/dd153782%28v=vs.110%29.aspx

https://msdn.microsoft.com/en-us/library/dd153782%28v=vs.110%29.aspx

A couple of salient points from the link:

链接中的几个要点:

"Other assemblies cannot bind to assemblies that are loaded without context, unless you handle the AppDomain.AssemblyResolve event"

“其他程序集无法绑定到在没有上下文的情况下加载的程序集,除非您处理 AppDomain.AssemblyResolve 事件”

"Loading multiple assemblies with the same identity without context can cause type identity problems similar to those caused by loading assemblies with the same identity into multiple contexts. See Avoid Loading an Assembly into Multiple Contexts."

“在没有上下文的情况下加载具有相同标识的多个程序集会导致类型标识问题,类似于将具有相同标识的程序集加载到多个上下文中所导致的问题。请参阅避免将程序集加载到多个上下文中。”

回答by Peter Kalef ' DidiSoft

I would suggest you to try Costura.Fody. Just don't forget to Install-Package Fody before Costura.Fody (in order to get the newest Fody!)

我建议你试试Costura.Fody。只是不要忘记在 Costura.Fody 之前安装包 Fody(为了获得最新的 Fody!)