2011-12-19 76 views
3

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

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

回答

6

这是不一样的;)

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

在MEF,基数是非常重要的,所以当你指出要导入的东西实例符合合同规定,只能有一个来源。如果找到多个导出,则由于基数不匹配而引发异常。

[Import]功能不包含特殊的逻辑来处理IEnumerable<T>,所以从它的角度来看,它是只是一个合同一样。

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

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

但是,这样的特殊外壳意味着某处执行的代码违反了Liskov Substitution Principle,这又违反了POLA,所以在这种情况下,我倾向于支持MEF设计师。寻求更明确的API可能会降低可发现性,但可能会更安全一些。

+0

感谢您的澄清。在我的情况下,恼人的是'compositionContainer.ComposeParts(this);'没有抛出异常,而是我的ImportMany导入是其中一个依赖关系。只有提示是关于拒绝导出的日志输出。这当然是由设计,幸运的是我找到了mefx工具来诊断问题。如果对象图很大,这种错误可能很难追踪。 – Ahe 2011-12-21 12:19:00

2

为了简化略上面的回答:如果有多个匹配的出口

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

如果我有,我想导入IDataAccessLayer,应该永远只能是一家出口可用 - 我永远不会被同时写入2个数据库,所以我用[Import],以确保只有一个会存在。

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

相关问题