首先让我说,我的MEF经验有限,并且之前使用Castle和Unity完成了我的目标。我希望MEF可以做类似的事情。
简而言之,我需要的是一个可以按名称实例化对象的工厂类。更具体地说,我将有一个抽象基类,如:
public abstract class TheBaseClass { ... }
将从基类派生任意数量的子类:
public class OneSubClass : TheBaseClass { ... }
public class AnotherSubClass : TheBaseClass { ... }
在运行时,我需要一个可以调用的工厂,传递一个'key'值,以获得返回的特定子类实例:
var key = "AnotherSubClass";
TheBaseClass instance = TheFactory.CreateInstance(key);
在Castle和Unity中,我可以使用'key'作为名称注册类型,并在尝试从容器中解析实例时将此值用作查找。我以为我可以使用ExportMetadata完成同样的事情,但我仍然可以做到这一点。
这种方法背后的基本原理(如果有更好的方法)是我需要在运行时实例化一个强类型的子类,而不需要在编译时知道该类型,因为应用程序是可扩展的(导出的)类型可以通过外部组件添加。
有什么想法吗?
答案 0 :(得分:2)
这在MEF中的工作方式与您提到的其他IoC容器中的工作方式相同。
[Export("one", typeof(TheBaseClass)]
public class OneSubClass : TheBaseClass { ... }
[Export("two", typeof(TheBaseClass)]
public class AnotherSubClass : TheBaseClass { ... }
我在这里分配的“密钥”是"one"
和"two"
,但当然可以使用您喜欢的任何内容。
然后,您将该密钥与GetExport()
结合使用:
var catalog = new TypeCatalog(typeof(OneSubClass), typeof(AnotherSubClass));
var container = new CompositionContainer(catalog);
var two = container.GetExport<TheBaseClass>("two");
var value = two.Value;
一些笔记;不要忘记以这种方式释放从容器中获得的导出,例如使用container.ReleaseExport(two)
。
您还应该注意,您可以将其与任何目录一起使用 - 我刚刚选择TypeCatalog
作为示例,但其他目标同样有效。
答案 1 :(得分:2)
我建议使用强类型名称来避免错误输入错误。
为此,首先需要创建一个用作密钥的枚举:
public enum DerivedClassesKeyEnum
{
ONE,
TWO
}
然后创建自定义属性:
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
public class DirivedBaseExportAttribute : ExportAttribute
{
public DirivedBaseExportAttribute()
:base(typeof(TheBaseClass))
{ }
public DerivedClassesKeyEnum DerivedClassId { get; set; }
}
接下来,将此属性应用于yuor派生类:
[DirivedBaseExport(DerivedClassId=DerivedClassesKeyEnum.ONE)]
public class OneSubClass : TheBaseClass
{
}
在导入这些类的部分中,您声明了一个接口:
public interface IDerivedClassMetadata
{
DerivedClassesKeyEnum DerivedClassId{get;}
}
最后一点,在你的FactoryClass中:
public class TheFactory
{
[ImportMany]
public static IEnumerable<Lazy<TheBaseClass, IDerivedClassMetadata>> DerivedClasses { get; set; }
public static TheBaseClass CreateInstance(DerivedClassesKeyEnum id)
{
return DerivedClasses.Single(c => c.Metadata.DerivedClassId == id).Value;
}
}
简化代码只是为了说明用法。