使用 MEF,如果我尝试从存储在插件文件夹中的许多大型 DLL 中的每一个中读取元数据,是否会在访问元数据值之前将整个 DLL 复制到内存中?
据我所知,整个 DLL 将被加载到内存中。不过,这与 MEF 没有任何关系。将使用对Assembly.Load的调用来DirectoryCatalog
加载程序集(通过) 。此方法不是 MEF 的一部分,但它是 .NET Framework 的核心方法。大多数加载的程序集都是以这种方式加载的。如果您使用Process Explorer监视运行您的应用程序的进程,您可以看到虚拟大小将增加加载程序集的大小。因此,如果您加载巨大的程序集,您的进程的虚拟大小将会很高。AssemblyCatalog
如果是这样,有没有办法打开每个 DLL 文件,只将元数据读入内存以构建初始菜单 - 然后稍后通过 MEF 加载完整选择的 DLL?
有办法做到这一点。
一种方法是创建一个新的应用程序域,CompositionContainer
在新的 AppDomain 中创建并检查发现的部分。然后将这些部分的信息序列化到主 AppDomain。最后卸载新的 AppDomain。然后,您可以检查您真正需要哪些部件,并仅加载包含它们的程序集。可以在此答案中找到有关如何执行此操作的示例。
另一种方法是使用Mono.Cecil。这是一个很棒的库,可以帮助您在不加载程序集的情况下检查它们。您可以通过以下方法将其与MEF 的导出元数据结合使用:
public static bool IncludesTypeWithSpecificExportMetadata<T>(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 和程序集的一般加载行为。谢谢 !
我上面提到的书籍详细包括如何解析/加载程序集等等。还可以查看Suzanne Cook 的博客。
现在我想问你一件事。您真的需要将大文件嵌入到您的程序集中吗?如果您能找到另一种方法,那么您将不需要任何方法。你的插件引擎会有点简单。
最后我建议看看微软的智能客户端软件工厂。它几乎可以完成您提到的所有事情以及更多。理解它并感到舒适需要一些努力,但从长远来看,它可能会为您节省大量时间。