【问题标题】:How to persist MEF import and export information to disk如何将 MEF 导入和导出信息持久化到磁盘
【发布时间】:2012-09-08 05:20:45
【问题描述】:

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

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

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

【问题讨论】:

    标签: c# lazy-loading mef


    【解决方案1】:

    此问题的答案由 Kevin 在 MEF discussion list 上提供。事实证明,可以使用以下代码 sn-ps 从 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 对象序列化为字符串格式就是一个简单的问题。

    【讨论】:

    • 做得很好。正如您在我的一些问题中看到的那样,我不久前一直在寻找类似的东西,很快我将重新审视这个功能。感谢分享并花时间回答您自己的问题。
    • memberInfo 是从哪里来的memberInfo.GetAccessors()
    • @l33t 我更新了代码示例以包含获取memberInfo 对象的部分。我希望这更清楚。感谢您指出缺少的代码行。
    • 谢谢!您的代码不处理元数据,对吧?只有在构造函数和属性中注入的导入。对吗?
    • @l33t 不,默认情况下不会。我不太确定添加该功能有多难。到目前为止我还不需要它。
    【解决方案2】:

    我有同样的要求,最终实现了与@Petrik 在他的回答中提到的非常相似的东西。我的 LazyAssemblyLoading solution 可以在 GitHub 上找到。

    【讨论】:

      猜你喜欢
      • 2020-10-08
      • 1970-01-01
      • 1970-01-01
      • 2011-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-21
      • 2015-12-03
      相关资源
      最近更新 更多