MEF RegistrationBuilder导出特定的接口实现

cli*_*cky 3 c# mef composition

我有一个接口的多种实现,并且我只想以编程方式导出一个。我已经看过了RegistrationBuilder,它的AddMetaData()功能是,但这是为导出定义MetaData,而不是为特定值过滤。例如,我想做这样的事情:

public enum MyClassType { TypeA, TypeB }
public interface IClass {}
public interface ClassMetaData { MyClassType Type { get; } }

[ExportMetadata("Type", MyClassType.TypeA)]
public MyClassA : IClass
{
    public MyClassType Type { get { return MyClassType.TypeA; } }
}

[ExportMetadata("Type", MyClassType.TypeB)]
public MyClassB : IClass
{
    public MyClassType Type { get { return MyClassType.TypeB; } }
}

//...Then in my bootstrapping class where I set up the MEF container...

var registrationBuilder = new RegistrationBuilder();
registrationBuilder.ForTypesDerivesFrom<IClass>()....
// How do I specify a filter in ^ to say only export the implementation with MetaData.Type == MyClassA or instance.Type == MyClassA.
Run Code Online (Sandbox Code Playgroud)

Law*_*nce 5

+1的问题-自从4.5出现以来,我再也没有机会看过MEF,所以这迫使我不得不加快学习新RegistrationBuilder课程的速度!

我猜测您的示例不起作用的原因是,据我了解,该示例RegistrationBuilder旨在取代MEF在.NET 4.0之前非常依赖的属性的角色。这ExportMetadataAttribute是旧的做事方式的一部分,只是我的猜测,旧的和新的不能很好地结合在一起。

多亏了RegistrationBuilder您的加入,您可以完全实现所需的功能,而导出的类却不知道它们是使用MEF构造的。在我看来,这是从4.0开始的MEF的巨大改进。

首先让我们从要导出的类开始。首先,我定义MyMetadataAttribute类,该类封装了与我们要过滤的类型相关的元数据:

public enum MyClassType
{
    TypeOne,
    TypeTwo
}

[AttributeUsage(AttributeTargets.Class)]
public class MyMetadataAttribute: Attribute
{
    public MyMetadataAttribute(MyClassType type)
    {
        Type = type;
    }

    public MyClassType Type { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)

现在来看我可能要导出的类:

public interface IClass
{
}

[MyMetadata(MyClassType.TypeOne)]
public class MyClassA : IClass
{
    public MyClassType Type
    {
        get { return MyClassType.TypeOne; }
    }
}

[MyMetadata(MyClassType.TypeTwo)]
public class MyClassB : IClass
{
    public MyClassType Type
    {
        get { return MyClassType.TypeTwo; }
    }
}
Run Code Online (Sandbox Code Playgroud)

解决问题的关键是上的ForTypesMatching()方法RegistrationBuilder。该参数是一个谓词,该谓词采用类型并根据要在导出结果中包括类型而返回true或false。下面的代码演示了一个示例:

internal class Program
{
    private static void Main(string[] args)
    {
        var registrationBuilder = new RegistrationBuilder();
        registrationBuilder
            .ForTypesMatching<IClass>(t => FilterOnMetadata(t, MyClassType.TypeOne))
            .ExportInterfaces();
        var assemblyCatalog = new AssemblyCatalog(typeof (MyClassType).Assembly, registrationBuilder);
        var compositionContainer = new CompositionContainer(assemblyCatalog);
        var ic = new TestImportContainer();
        compositionContainer.ComposeParts(ic);
        var count = ic.ImportedParts.Count();
    }

    public static bool FilterOnMetadata(Type t, MyClassType classType)
    {
        var metadataAttribute = 
            (MyMetadataAttribute) t.GetCustomAttributes(true)
                .SingleOrDefault(at => at is MyMetadataAttribute);
        if (metadataAttribute != null)
            return metadataAttribute.Type == classType;
        return false;
    }

    private sealed class TestImportContainer
    {
        [ImportMany(typeof(IClass))]
        public IEnumerable<IClass> ImportedParts { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 假设您有一个实现“ IIntefaceOne”和“ IInterfaceTwo”的类“ T”。使用`Export()`配置此类将匹配类型为T的导入。使用`Export &lt;IInterfaceOne&gt;将把该类与导入类型为“ IIntefaceOne`”匹配。使用`ExportInterfaces()`将匹配类型为'IIntefaceOne`和`IInterfaceTwo`的导入。此评论可能无法很好地解释它。有一篇很棒的文章[here](http://msdn.microsoft.com/zh-cn/magazine/jj133818.aspx),我发现它真的很有用。 (2认同)