如何读取DLL插件中的MEF元数据而不将整个DLL复制到内存中?

背景:

我有兴趣使用MEF在使用C#和.NET 4.0的WinForm应用程序中提供插件架构,但我不清楚几件事情。

第一:我还没有在C#中构建DLL的工作,我对DLL程序集的概念以及DLL如何正常加载到内存中有点模糊(意思是,所有一次或根据需要一块一块)

意图:

该程序将是一个机器硬件控制框架,将由一个主要的WinForm GUI组成,这是一个具有基本工具栏,菜单等的通用环境 – 但没有批量GUI内容。 (想想:MDI Parent,但实际上并非如此)。

插件提供特定机器的所有控件。 许多可能的插件中的每一个都可能包含30到50个大型UserControl,每个用户控件都包含许多WinForm控件和大量支持代码,构成了各种机器控制面板。

这意味着主程序是一个轻量级的通用框架,插件包含将在主程序用户界面中显示的大量GUI控件和function,包括许多图标,图像和其他资源。 这将使插件DLL可能非常大。

目标是允许用户从菜单中选择一个插件,然后在选择时加载并运行插件,然后插件将大部分空的主GUI填充面板,菜单和工具箱。

为此,我需要首先从每个插件中提取元数据以填充程序的初始菜单,其中包括插件标题,描述,图标,版本号和其他信息位。

以下是问题:

使用MEF,如果我尝试从存储在插件文件夹中的每个大型DLL中读取元数据,是否会在访问元数据值之前将整个DLL复制到内存中?

如果是这样,有没有办法打开每个DLL文件,只读取元数据到内存中构建初始菜单 – 然后通过MEF加载完整选定的DLL?

我假设用于通过MEF读取插件的典型DirectoryCatalog和AggregateCatalog模板将所有发现的DLL复制到内存中并将它们存储在目录集合中。

DLL是否包含一个连续的代码块(程序集),或者它们是否可以包含多个单独的块,这些块根据需要单独索引并复制到内存中(多个程序集)?

我可能不了解基本面,也许可能会混淆条款。 我将非常感谢对MEF,DLL和程序集的加载行为的任何了解。 谢谢 !

使用MEF,如果我尝试从存储在插件文件夹中的每个大型DLL中读取元数据,是否会在访问元数据值之前将整个DLL复制到内存中?

据我所知,整个DLL将被加载到内存中。 这与MEF没有任何关系。 DirectoryCatalog将使用对Assembly.Load的调用加载程序集(通过AssemblyCatalog )。 此方法不是MEF的一部分,但它是.NET Framework的核心方法。 大多数加载的程序集都是以这种方式加载的。 如果使用Process Explorer监视运行应用程序的进程 ,则可以看到虚拟大小将增加已加载程序集的大小。 因此,如果您加载大型程序集,您的进程的虚拟大小将很高。

如果是这样,有没有办法打开每个DLL文件,只读取元数据到内存中构建初始菜单 – 然后通过MEF加载完整选定的DLL?

有办法做到这一点。

一种方法是创建一个新的应用程序域 ,在新的AppDomain中创建CompositionContainer并检查发现的部分。 然后将有关这些部分的信息序列化到主AppDomain。 最后卸载新的AppDomain。 然后,您可以检查您真正需要的部件,并仅加载包含它们的部件。 有关如何执行此操作的示例可以在此答案中找到。

另一种方法是使用Mono.Cecil 。 这是一个很棒的库,可以帮助您检查程序集而不加载它们。 您可以使用以下方法将其与MEF的导出元数据结合使用:

 public static bool IncludesTypeWithSpecificExportMetadata(string assemblyPath, string name, T value) { AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyPath); bool typeWasFound = false; foreach (TypeDefinition typeDefinition in assemblyDefinition.MainModule.GetTypes()) { foreach (CustomAttribute customAttribute in typeDefinition.CustomAttributes) { if (customAttribute.AttributeType.FullName == typeof(ExportMetadataAttribute).FullName) { string actualName = (string)customAttribute.ConstructorArguments[0].Value; T actualValue = (T)((CustomAttributeArgument)customAttribute.ConstructorArguments[1].Value).Value; if (actualName.Equals(name) && actualValue.Equals(value)) { typeWasFound = true; } } } } return typeWasFound; } 

给定一个程序集文件路径和一个名称/值对,此方法将使用Mono.Cecil检查程序集,并查找使用ExportMetadataAttribute和相同名称/值对修饰的类型。

我假设用于通过MEF读取插件的典型DirectoryCatalog和AggregateCatalog模板将所有发现的DLL复制到内存中并将它们存储在目录集合中。

真正。

DLL是否包含一个连续的代码块(程序集),或者它们是否可以包含多个单独的块,这些块根据需要单独索引并复制到内存中(多个程序集)?

我不知道这个。 您可以在Don Box的“Essential .NET Volume 1”或Jeffrey Richter的“C#via CLR”中找到答案。

我可能不了解基本面,也许可能会混淆条款。 我将非常感谢对MEF,DLL和程序集的加载行为的任何了解。 谢谢 !

我上面提到的书籍详细说明了如何解决/加载assembly等等。 还可以看看Suzanne Cook的博客 。

现在我想问你一件事。 您真的需要将大文件嵌入到程序集中吗? 如果你能找到另一种方式,那么你将不需要任何这种方式。 你的插件引擎会有点简单。

最后我建议看看微软的智能客户端软件工厂 。 它可以完成您提到的所有内容以及更多内容。 需要花费一些精力来理解它并对它感到舒服,但从长远来看它可能会节省你的时间。