我们可以为重复的IntoSet项目构建失败吗?

时间:2018-06-05 14:58:36

标签: dagger-2

当我们使用@IntoSet多重绑定并注册多个相同的项目时,Dagger将使用其中一个项目并默默忽略其他项目。
有没有办法配置dagger来检查重复项并使构建失败?
或者有解决方法吗?

1 个答案:

答案 0 :(得分:1)

  

有没有办法配置dagger来检查重复项并使构建失败?

不,即使是假设,这也是不可能的,因为"重复项目的概念"取决于equalshashCode运行时概念。即使返回的对象是完全相同的实例或常量,Dagger也只能在编译时读取方法签名,而不是代码。它无法检测单独的@Provides @IntoSet方法是否返回相等的值或文字。

我怀疑Dagger本身也没有在运行时检查;它将等于检查和重复数据删除给Set实现。 The Set interface defines its behavior there.

  

为什么要注册多个项目,然后只使用其中一个项目?

你是对的,行为应该是确定性的,而不是随机任意,这是你的一部分原因可以得到一个Set(无序)但不是List(有序)。您随机调用输出,但这只是因为您要区分彼此声明自己equal的两个对象。如果我和朋友分开两张5美元的钞票,我不会认为结果是随机的或不确定的,前提是他和我同意这些账单彼此相等。

就Java而言,你有同一个对象的两个副本。如果你想要一个插件接口,这可能是有意义的,其中ModuleA安装@Binds @IntoSet Plugin bindFooPlugin(FooPlugin foo);而ModuleB安装@Binds @IntoSet Plugin bindFooPlugin(FooPlugin foo);。虽然你可以用任何一种方式对理想行为做出好的论证,但我希望FooPlugin只需要Set<Plugin>一次,除非它的equals实现表明插件实例彼此不同,其中我希望每个@IntoSet绑定一个。

至于解决方法,你可以:

  • 调整equals实施。您会看到此行为,因为这两个对象是相同的。如果你不是说他们是平等的,那么希望你可以控制的代码。

  • 为了equals而包装对象。 Guava通过Equivalence.identity().wrap(obj)执行此操作,这需要一些额外的实例,但允许您覆盖内部对象的equals概念。

  • 使用Multibindings Map。与@IntoSet或@IntoMap的返回值不同,Dagger坚持认为映射键是编译时常量定义为注释,哪个有a strict definition of equality that can be checked at compile time。虽然您无法在此处使用自己的自定义对象,但Dagger does break at compile-time for duplicate Map keys

    StringBuilder message =
        new StringBuilder("The same map key is bound more than once for ")
        .append(mapBindingKey);
    

    当然,如果您想要使用该地图并通过Map.values()返回经过检查确定的值集,那么您也可以这样做。