繁体   English   中英

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

[英]How to persist MEF import and export information to disk

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

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

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

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

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

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对象序列化为字符串格式是一个简单的问题。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM