对于我在this question中描述的应用程序,我想使用MEF扫描可用的插件程序集,然后以序列化格式存储所有可用的导入和导出信息(例如一组字符串或内存流) 。这是必要的,因为我需要通过AppDomain边界传输导入和导出信息而不用加载插件程序集(基本上我想延迟加载插件)。我找到了一些引用,例如this one或this one,但没有一个链接让我知道如何:
我想我可以使用ReflectionModelServices class来创建导入/导出定义,但仍然会留下序列化和反序列化部分。任何人都可以向我指出一些例子,文档或者为我提供如何进行这些步骤的建议吗?
答案 0 :(得分:7)
凯文在MEF discussion list提供了这个问题的答案。事实证明,可以使用以下代码片段从MEF ExportDefinition和ImportDefinition数据结构中提取所有必需信息。
第一步是将程序集类型加载到目录中。然后,对于目录中的每个部分,迭代导入和导出定义。导出定义只能放在类型,方法,属性和字段上(我的代码目前忽略)。因此,要处理导出,可以使用以下代码。
var exports = new List<Tuple<string, MemberInfo>>();
foreach (var export in part.ExportDefinitions)
{
var memberInfo = ReflectionModelServices.GetExportingMember(export);
Tuple<string, MemberInfo> exportDefinition = null;
switch (memberInfo.MemberType)
{
case MemberTypes.Method:
exportDefinition = new Tuple<string, MemberInfo>(export.ContractName, memberInfo.GetAccessors().First() as MethodInfo);
break;
case MemberTypes.NestedType:
case MemberTypes.TypeInfo:
exportDefinition = new Tuple<string, MemberInfo>(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<string, MemberInfo>(export.ContractName, property);
break;
default:
throw new NotImplementedException();
}
exports.Add(exportDefinition);
}
为了处理只能放在属性,参数和字段(再次被忽略)上的导入,可以使用以下代码:
public void ExtractImports()
{
var imports = new List<Tuple<string, string>>();
foreach (var import in part.ImportDefinitions)
{
SerializedImportDefinition importDefinition = !ReflectionModelServices.IsImportingParameter(import)
? importDefinition = CreatePropertyImport(import)
: importDefinition = CreateConstructorParameterImport(import);
}
}
private Tuple<string, string> 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<string, string>(import.ContractName, property.ToString());
}
private Tuple<string, string> CreateConstructorParameterImport(ImportDefinition import)
{
var parameterInfo = ReflectionModelServices.GetImportingParameter(import);
return new Tuple<string, string>(import.ContractName, parameterInfo.Value.ToString());
}
请注意,似乎无法通过方法参数提供导入,因此上面的代码不支持这些。
一旦处理了所有导出和导入,将存储的MemberInfo对象序列化为字符串格式是一个简单的问题。
答案 1 :(得分:0)
我有同样的要求,最终实现了与@Petrik在答案中提到的非常类似的东西。我的LazyAssemblyLoading solution可在GitHub上找到。