我有一个简单的界面和类:
interface Foo {
fun value(): Int
}
class FooImpl : Foo {
override fun value() = 100
}
现在我想为Foo
创建一个工厂并能够注入它。我尝试使用以下代码:
interface FooFactory : () -> Foo
@Module
class AppModule {
// provides FooFactory
@Provides
fun provideFooFactory() = object : FooFactory {
override fun invoke() = FooImpl()
}
// uses FooFactory
@Provides
fun provideFoo(factory: FooFactory) = factory()
}
@Component(modules = [AppModule::class])
interface AppComponent {
fun foo(): Foo
}
注入Foo
的地方:
@Test
fun test() {
val component = DaggerAppComponent.builder().build()
val foo = component.foo()
Assert.assertEquals(100, foo.value())
}
完美的作品!但是,我认为,将FooFactory
定义为接口是一种丑陋,所以我试图替换:
interface FooFactory : () -> Foo
使用:
typealias FooFactory = () -> Foo
现在我收到编译时错误:
Error:Gradle:
kotlin.jvm.functions.Function0<? extends net.chmielowski.daggerkotlin.Foo>
cannot be provided without an @Provides-annotated method.
如果我理解正确,问题是在构建过程中(在Dagger代码生成之前)内联typealias
并且Dagger在找出哪个提供程序为参数化(通用)类型提供实例时遇到问题{ {1}}。
顺便说一下:如果我删除了Function0<? extends Foo>
并且只在任何地方使用Foo
,则问题不会发生。这意味着问题不在于泛型本身,而在于抽象类型参数化的类。
此问题的解决方案是什么?
要明确 - 使用FooImpl
代替typealias
背后的理由是能够写下:
interface
而不是:
@Provides
fun provideFooFactory() = { FooImpl() }
答案 0 :(得分:0)
实施
@Provides fun provideFooFactory() = { FooImpl() }
表示返回类型为() -> FooImpl
,会转换为Function0<? extends FooImpl>
,匕首无法与Function0<? extends Foo>
匹配。相反,您必须确保provideFooFactory
具有正确的返回类型。
这可以通过下载来实现
@Provides fun provideFooFactory() = { FooImpl() as Foo }
或明确声明类型
@Provides fun provideFooFactory(): FooFactory = { FooImpl() }
答案 1 :(得分:0)
今天我遇到了类似的问题,当时我正在使用kotlin lambda通过匕首返回值。
DaggerModule.kt
@Provides
fun provideFoo() = {
foo.get()
}
BarClass.kt
BarClass( private val fooFunction: () -> Foo )
我遇到的错误与您看到的匕首找不到提供的方法相同。
(如上所述)
kotlin.jvm.functions.Function0<? extends net.chmielowski.daggerkotlin.Foo>
cannot be provided without an @Provides-annotated method.
对我来说,在提供程序中明确声明类型是不够的。 相反,该解决方案与kotlin和java如何处理泛型有关。基本上,当将该函数转换为Java时(匕首仍然在后台运行),它添加了 <?将Foo> 扩展到方法签名。您可以使用接收类的构造函数中的 @JvmSuppressWildcards 注释抑制此行为。
BarClass( private val fooFunction: () -> @JvmSuppressWildcards Foo )