为什么MEF有[ImportMany]而不仅仅是[Import]

时间:2011-12-19 14:16:28

标签: dependency-injection inversion-of-control mef

我刚刚在我的mef应用程序中找到了一个问题;问题是,我的[Import]媒体资源中有[ImportMany]而不是IEnumerable<IFoo>。我开始想知道为什么。 MEF看到注射目标是“集合”并且可以确定需要集合而不是单个元素。至少Ninject是这样工作的。

有没有人了解为什么需要[ImportMany]?我能想到的唯一原因是人们可能想要[Export(typeof(IEnumerable<IBar>)] public IEnumerable<Bar> { get; },但这真的是这个设计的原因吗?我敢打赌,我不是唯一一个调试过这种错误的人。

2 个答案:

答案 0 :(得分:6)

它不一样;)

[Import]表示您要根据合同导入单件。在MEF中,合约只是一个字符串,当您导入类型(如IEnumerable<IBar>)时,您实际上是根据合同导入的,该合同只是该类型的名称

在MEF中,基数非常重要,因此当您声明要导入符合所述合同的单个实例时,只能有一个单个来源。如果找到多个导出,则由于基数不匹配而抛出异常。

[Import]功能不包含处理IEnumerable<T>的特殊逻辑,因此从它的角度来看,它只是一个像其他一切一样的契约。

然而,[ImportMany]属性尤其适用于弥合这一差距。它对所述合同的任何数量的出口都接受零。这意味着,您可以将{em>多个导出IEnumerable<IBar>散布在多个程序集中,而不是{em>单导出IBar,而且永远不会是基数不匹配。

最后它是一个设计哲学。 MEF可能有关于IEnumerable<T>的特殊内置知识。 Autofac(显然是Ninject)就是这样做的,并称之为Relationship Type

然而,像这样的特殊套管意味着实施代码某处违反Liskov Substitution Principle,这又会导致POLA违规,所以在这种情况下,我倾向于与MEF设计师站在一边。寻求更明确的API可能会降低可发现性,但可能会更安全一些。

答案 1 :(得分:2)

稍微简化上述答案:

    如果有多个匹配导出,
  • [Import]将抛出异常。
  • [ImportMany]将加载多个匹配的导出,而不会抛出错误。

如果我有一个我要导入的IDataAccessLayer,那么应该只有一个导出可用 - 我永远不会同时写入2个数据库,所以我使用[Import]来确保只存在一个

如果我想加载许多不同的BusinessObjects,我将使用[ImportMany]因为我需要许多不同类型的BusinessObjects。