如何将MEF导入和导出信息保存到磁盘

对于我在这个问题中描述的应用程序,我想使用MEF扫描可用的插件程序集,然后以序列化格式(例如一组字符串或内存流)存储所有可用的导入和导出信息。 这是必要的,因为我需要通过AppDomain边界传输导入和导出信息而不加载插件程序集(基本上我想延迟加载插件)。 我找到了一些参考文献,比如这个或者这个,但没有一个链接让我知道如何:

  • 从程序集中提取所有导入和导出
  • 序列化所有必需的导入/导出信息
  • 然后再将序列化信息重新水合成import和出口。

我想我可以使用ReflectionModelServices类来创建导入/导出定义但仍然保留序列化和反序列化部分。 任何人都可以向我指出一些例子,文档或者提供关于如何进行这些步骤的建议吗?

这个问题的答案由Kevin在MEF讨论列表中提供 。 事实certificate,可以使用以下代码片段从MEF ExportDefinition和ImportDefinition数据结构中提取所有必需信息。

第一步是将程序集类型加载到目录中。 然后,对于目录中的每个部分,迭代导入和导出定义。 导出定义只能放在类型,方法,属性和字段上(我的代码目前忽略)。 因此,要处理导出,可以使用以下代码。

var exports = new List>(); foreach (var export in part.ExportDefinitions) { var memberInfo = ReflectionModelServices.GetExportingMember(export); Tuple exportDefinition = null; switch (memberInfo.MemberType) { case MemberTypes.Method: exportDefinition = new Tuple(export.ContractName, memberInfo.GetAccessors().First() as MethodInfo); break; case MemberTypes.NestedType: case MemberTypes.TypeInfo: exportDefinition = new Tuple(export.ContractName, memberInfo.GetAccessors().First() as Type); break; case MemberTypes.Property: // this is a bit ugly because we assume that the underlying methods for a property are named as: // get_PROPERTYNAME and set_PROPERTYNAME. In this case we assume that exports always // have a get method. var getMember = memberInfo.GetAccessors().Where(m => m.Name.Contains("get_")).First(); var name = getMember.Name.Substring("get_".Length); var property = getMember.DeclaringType.GetProperty(name); exportDefinition = new Tuple(export.ContractName, property); break; default: throw new NotImplementedException(); } exports.Add(exportDefinition); } 

为了处理导入,导入只能放在属性,参数和字段(再次被忽略)上,可以使用以下代码:

 public void ExtractImports() { var imports = new List>(); foreach (var import in part.ImportDefinitions) { SerializedImportDefinition importDefinition = !ReflectionModelServices.IsImportingParameter(import) ? importDefinition = CreatePropertyImport(import) : importDefinition = CreateConstructorParameterImport(import); } } private Tuple CreatePropertyImport(ImportDefinition import) { var memberInfo = ReflectionModelServices.GetImportingMember(import); if (memberInfo.MemberType != MemberTypes.Property) { throw new ArgumentOutOfRangeException("import"); } // this is a bit ugly because we assume that the underlying methods for a property are named as: // get_PROPERTYNAME and set_PROPERTYNAME. In this case we assume that imports always // have a set method. var getMember = memberInfo.GetAccessors().Where(m => m.Name.Contains("set_")).First(); var name = getMember.Name.Substring("set_".Length); var property = getMember.DeclaringType.GetProperty(name); return new Tuple(import.ContractName, property.ToString()); } private Tuple CreateConstructorParameterImport(ImportDefinition import) { var parameterInfo = ReflectionModelServices.GetImportingParameter(import); return new Tuple(import.ContractName, parameterInfo.Value.ToString()); } 

请注意,似乎无法通过方法参数提供导入,因此上面的代码不支持这些。

处理完所有导出和导入后,将存储的MemberInfo对象序列化为字符串格式是一个简单的问题。

我有同样的要求,并最终实现了与@Petrik在他的回答中提到的非常类似的东西。 我的LazyAssemblyLoading解决方案可在GitHub上获得。