【问题标题】:Why MEF has [ImportMany] and not just [Import]为什么 MEF 有 [ImportMany] 而不仅仅是 [Import]
【发布时间】:2011-12-19 14:16:27
【问题描述】:

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

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

【问题讨论】:

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


    【解决方案1】:

    不一样;)

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

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

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

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

    归根结底,这是一种设计理念。 MEF 可能对IEnumerable<T> 有特殊的内置知识。 Autofac(显然是 Ninject)就是这样做的,并称之为 Relationship Type

    但是,像这样的特殊情况意味着实现代码在某处违反了Liskov Substitution Principle,这又可能导致POLA 违规,因此在这种情况下,我倾向于站在 MEF 设计者一边。使用更明确的 API 可能会降低可发现性,但可能会更安全。

    【讨论】:

    • 感谢您的澄清。在我的情况下,烦人的事情是compositionContainer.ComposeParts(this); 没有抛出异常,而是我在其他地方的 ImportMany 导入是一个依赖项短。唯一的提示是有关拒绝导出的日志输出。这当然是设计使然,幸运的是我找到了诊断问题的 mefx 工具。如果对象图很大,这种错误可能很难跟踪。
    【解决方案2】:

    为了稍微简化上面的答案:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-21
      • 2012-05-04
      相关资源
      最近更新 更多