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

Dependency injection 为什么MEF拥有[ImportMany]而不仅仅是[Import],dependency-injection,inversion-of-control,mef,Dependency Injection,Inversion Of Control,Mef,我刚刚在我的mef应用程序中找到了一个问题;问题是,我的IEnumerable属性中有一个[Import]而不是[ImportMany]。我开始想为什么。MEF认为注入目标是一个“集合”,可以确定需要集合而不是单个元素。至少Ninject是这样工作的 有人知道为什么需要[ImportMany]?我能想到的唯一原因是人们可能想要[Export(typeof(IEnumerable)]public IEnumerable{get;},但这真的是这种设计的原因吗?我打赌我不是唯一一个调试这种错误的人。

我刚刚在我的mef应用程序中找到了一个问题;问题是,我的
IEnumerable
属性中有一个
[Import]
而不是
[ImportMany]
。我开始想为什么。MEF认为注入目标是一个“集合”,可以确定需要集合而不是单个元素。至少Ninject是这样工作的

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

这不一样;)

[Import]
表示您希望根据合同导入单个内容。在MEF中,契约只是一个字符串,当您导入一个类型(如
IEnumerable
)时,实际上是根据一个契约进行导入,而该契约只是该类型的名称

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

[Import]
功能不包含处理
IEnumerable
的特殊逻辑,因此从它的角度来看,它只是一个契约,与其他任何东西一样

然而,
[ImportMany]
属性的存在尤其是为了弥补这一差距。它接受所述合同的零到任意数量的出口。这意味着,您可以将多个
IBar
导出分散在多个程序集上,而不是单个导出
IEnumerable
,并且永远不会出现基数不匹配

最终,这是一种设计哲学。MEF本可以拥有关于
IEnumerable
的特殊内置知识。Autofac(显然是Ninject)做到了这一点,并称之为


然而,这样的特殊外壳意味着实现代码在某个地方违反了,这又会导致违反,所以在这种情况下,我倾向于站在MEF设计者一边。选择更明确的API可能会降低可发现性,但可能会更安全一些。

要稍微简化上述答案:

  • 如果有多个匹配的导出,
    [Import]
    将引发异常
  • [ImportMany]
    将加载多个匹配的导出,而不会引发错误
如果我有一个IDataAccessLayer要导入,那么应该只有一个导出可用-我永远不会同时写入两个数据库,所以我使用
[import]
确保只有一个数据库存在


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

感谢您的澄清。在我的例子中,恼人的是
compositionContainer.ComposeParts(这个)
没有抛出异常,相反,我的ImportMany import别处缺少一个依赖项。唯一的提示是关于拒绝导出的日志输出。这当然是出于设计,幸运的是我找到了mefx工具来诊断问题。如果对象图很大,这种错误很难跟踪。