2012-08-26 82 views
3

我正在使用MEF来编写来自几个程序集的导出类型。我正在使用一个基类,它应该是派生类中指定的ImportMany依赖项。它看起来是这样的:MEF的ImportMany在基类中导入所有组件的所有导出 - 如何防止这种情况?

基地大会:

public abstract class BaseClass 
{ 
    [ImportMany(typeof(IDependency)] 
    public IEnumerable<IDependency> Dependencies { get; private set; } 

    protected BaseClass() 
    { 
     var catalog = GetCatalog(); 
     var container = new CompositionContainer(catalog); 
     container.ComposeParts(this); 
    } 

    protected abstract ComposablePartCatalog GetCatalog(); 
} 

议会答:

[Export(typeof(BaseClass))] 
public class MyA : BaseClass 
{ 
    protected override ComposablePartCatalog GetCatalog() 
    { 
     return new AssemblyCatalog(Assembly.GetExecutingAssembly()); 
    } 
} 

[Export(typeof(IDependency)] 
public class DependencyA1 : IDependency {} 

[Export(typeof(IDependency)] 
public class DependencyA2 : IDependency {} 

大会B:

[Export(typeof(BaseClass))] 
public class MyB : BaseClass 
{ 
    protected override ComposablePartCatalog GetCatalog() 
    { 
     return new AssemblyCatalog(Assembly.GetExecutingAssembly()); 
    } 
} 

[Export(typeof(IDependency)] 
public class DependencyB1 : IDependency {} 

[Export(typeof(IDependency)] 
public class DependencyB2 : IDependency {} 

我然后撰写一切都在底座组件:

static void Main(string[] args) 
{ 
    DirectoryCatalog catalog = new DirectoryCatalog(path, "*.dll"); 
    var container = new CompositionContainer(catalog); 
    IEnumerable<BaseClass> values = container.GetExportedValues<BaseClass>(); 

    // both BaseClass instances now have 4 Dependencies - from both Assemby A and Assembly B! 
} 

我遇到的,当我使用MEF撰写既MyAMyB的问题,每个包含出口IDependency -ies从两个组件!我只想要MyA包含出口DependencyA1DependencyA2,与MyB相同。

我知道我可能应该为此使用依赖注入容器,但我希望可以使用MEF吗?

+0

只是一些注意事项 - 用构造函数做构图 - 我已经看到了很多,这不是一个好设计的想法。建议您的应用程序的一个部分处理与组合容器有关的所有事情,这就是所谓的* CompositionRoot *。理想情况下,您的组件应设计为不受任何扩展性或IoC容器的影响,因此您可以独立构建和测试它们。为了做到这一点,虽然旋转一个'CompositionContainer'的新实例相对便宜,但编目创建可能很昂贵。 –

+0

另一点需要考虑的是,您正在从构造函数调用虚拟方法,这意味着您不能再保证您的'BaseClass'构造函数将完成,因为它现在依赖于回调函数的继承层次结构。如果你的'override'方法试图使用你的子类类型的实例成员 - 你最终可能抛出'NullReferenceException'实例,因为这些实例成员可能还没有被初始化。 –

+0

@MatthewAbbott RE构造函数中的虚拟调用,你是对的,这只是为了这个例子。在我的“真实”应用程序中,我没有从构造函数调用虚拟方法。 –

回答

1

在另一个组合物的鼻子下面做一个组合物是相当讨厌的;)。

所以我会解决手动调用container.GetExportedValues并在构造函数中通过你自己设置属性的方式来摆脱[ImportMany]全部。 并且它不在外部组合物上操作。

HTH 阿里尔

+0

优秀!我删除了'ImportMany'属性,并用'GetExportedValues '的简单调用代替它。这解决了问题!谢了哥们! –

1

你正在做的MEF周围一些奇怪的舞蹈用这种方法,你基本上构成BaseClass的多次将根据出现不同的结果上组成发生最后一次。当前编写代码的方式是在Main中发生的组合将是最后一次设置ImportMany的组合,因为这发生在构造函数调用BaseClass之后。与Ariel类似,我会建议您不要在同一个对象上做多个作品。

如果你必须做这样的事情与MEF这里有一些方法,我可以看到它可能工作: 1)不要做第二个组成构造,而是使用IPartImportsSatisfiedNotification和OnImportsSatisifed做第二次composistion,尽管当你第二次创作时要留意第二次调用这个方法。 2)按照Ariel的建议,不要使用ImportMany,而是简单地使用GetExportedValues将该字段设置为其他装配体级别目录。请记住,仍然在做一个大的假设,即每个程序集只有一个派生类,否则您仍会遇到重叠。 3)您可以将ImportMany移动到派生类中,并为每个派生类型(即IADependency或IBDendency)导入唯一的依赖类型。 4)您可以使用元数据来筛选特定派生类型的导入。

我不确定这些都是完美的,但如果我选择一个选项,我可能会去#4的一些变化,并使用元数据过滤进口之间。请参阅How does MEF determine the order of its imports?,其中显示了如何对导入进行排序,但存在用于筛选它们的类似代码示例。

相关问题