如果您创建一个使用其他程序集中的东西的类库,是否可以将这些其他程序集作为某种资源嵌入到类库中?
即,不是将MyAssembly.dll,SomeAssembly1.dll和SomeAssembly2.dll放在文件系统上,而是将其他两个文件捆绑到MyAssembly.dll中,并且可以在其代码中使用.
我也对.NET程序集为.dll文件的原因感到有些困惑.在.NET之前,这种格式不存在吗?所有.NET程序集都是DLL,但并非所有DLL都是.NET程序集吗?为什么他们使用相同的文件格式和/或文件扩展名?
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中.
查看ILMerge以合并程序集.
我也对.NET程序集为.dll文件的原因感到有些困惑.在.NET之前,这种格式不存在吗?
是.
是所有.NET程序集DLL,
无论是DLL还是EXE通常 - 但也可以是netmodule.
但并非所有的DLL都是.NET程序集?
正确.
为什么他们使用相同的文件格式和/或文件扩展名?
为什么它应该有所不同 - 它有同样的目的!
您可以将程序集(或任何文件,实际上)作为资源嵌入(然后使用ResourceManager
类来访问它们),但如果您只想组合程序集,最好使用ILMerge之类的工具.
EXE和DLL文件是Windows可移植的可执行文件,它们通用到足以容纳未来类型的代码,包括任何.NET代码(它们也可以在DOS中运行但只显示一条消息,表明它们不应该在DOS中运行).它们包括启动.NET运行时的指令(如果尚未运行).单个程序集也可以跨越多个文件,尽管情况并非如此.
注意ILMerge不能与XAML等嵌入式资源一起使用,因此WPF应用程序等需要使用Cheeso的方法.