+1 问题 - 自 4.5 发布以来,我没有机会查看 MEF,所以它迫使我跟上新添加的RegistrationBuilder
课程!
我猜您的示例不起作用的原因是因为据我了解,它RegistrationBuilder
旨在替换 MEF 严重依赖的属性的角色,直到 .NET 4.0。这ExportMetadataAttribute
是旧的做事方式的一部分,我只是猜测新旧不能很好地结合在一起。
多亏了添加,RegistrationBuilder
您可以完全实现您想要的,而导出的类不知道它们是使用 MEF 构建的。在我看来,这是 MEF 与 4.0 相比的巨大改进。
首先让我们从要导出的类开始。首先,我定义了一个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; }
}
现在来了我可能想要导出的类:
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; }
}
}
解决你的问题的关键是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; }
}
}