4

For my application as described in this question I want to use MEF to scan the available plugin assemblies and then store all the available import and export information in a serialized format (e.g. a set of strings or a memory stream). This is necessary because I need to transfer the import and export information over an AppDomain boundary without loading the plugin assemblies (essentially I want to delay load the plugins). I found some references, for instance this one or this one but none of the links gave me any idea how to:

  • Extract all the imports and exports from an assembly
  • Serialize all the required import/export information
  • And then later on re-hydrate the serialized information back into imports and exports.

I think I can use the ReflectionModelServices class to create Import/Export definitions but that still leaves the serialization and deserialization parts. Can anybody point me to some examples, documentation or provide me with suggestion as to how to go about these steps?

4

2 に答える 2

7

この質問に対するこの回答は、MEF ディスカッション リストで Kevin によって提供されました。次のコード スニペットを使用して、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オブジェクトを文字列形式にシリアル化するという簡単な問題になります。

于 2012-10-11T23:43:33.033 に答える
0

私は同じ要件を持っていて、@Petrikが彼の答えで言及したものと非常によく似たものを実装することになりました。私のLazyAssemblyLoading ソリューションは GitHub で入手できます。

于 2016-09-21T20:32:47.457 に答える