我正在研究如何使用 dagger 创建 Set(s) 并将其注入 Maps,其 kotlin 代码如下所示
首先没有任何意义的是使用 kotlin
@ClassKey(ErikTenHag::class)
,
即使
ClassKey
注释的实现如下:-
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RUNTIME)
@MapKey
public @interface ClassKey {
Class<?> value();
}
例如当我尝试设置时使用 java.lang.Class NOT KClass
@ClassKey(ErikTenHag::class.java)
我收到此错误消息
接下来,当我为地图制作注入位置时,如下所示:-
@JvmSuppressWildcards
data class FootballLeague @Inject constructor(val teamMap: Map<@JvmSuppressWildcards KClass<*>, Set<Player>>) {
我遇到编译时错误
[Dagger/MissingBinding] java.util.Map<kotlin.reflect.KClass<?>,java.util.Set<Player>> cannot be provided without an @Provides-annotated method.
当我制作注射部位时
@JvmSuppressWildcards
data class FootballLeague @Inject constructor(val teamMap: Map<@JvmSuppressWildcards Class<*>, Set<Player>>) {
我的代码编译良好并按要求工作。
我期望《匕首 2》应该有意义还是我错过了什么?
我不喜欢在类定义中使用“*”,我宁愿设置一个具体的接口或类,但是当我这样做时我无法让匕首进行编译...
我尝试按如下方式制作注射部位:-
@JvmSuppressWildcards
data class FootballLeague<M: Manager> @Inject constructor(val teamMap: Map<@JvmSuppressWildcards Class<M>, Set<Player>>) {
但是我的代码无法编译并出现错误
error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<Manager>,java.util.Set<Player>> cannot be provided without an @Provides-annotated method.
我必须使用“*”,还是有一种方法可以限制类类型?
@Module
@InstallIn(SingletonComponent::class)
class FootballTeamModule {
@Provides
@ElementsIntoSet
@Named("LiverpoolPlayers")
fun providesLiverpoolPlayers(mohamedSalah: MohamedSalah, virgilVanDyke: VirgilVanDyke): Set<Player> {
return HashSet<Player>(listOf(mohamedSalah, virgilVanDyke))
}
@Provides
@ElementsIntoSet
@Named("ManchesterPlayers")
fun providesManchesterPlayers(harryMaguire: HarryMaguire, masonMount: MasonMount, casimiro: CarlosCasimiro): Set<Player> {
return HashSet<Player>(listOf(harryMaguire, masonMount, casimiro))
}
@Provides
@IntoMap
@ClassKey(JurgenKlopp::class)
//@StringKey("JurgenKlopp")
fun providesLiverpool(@Named("LiverpoolPlayers") players: Set<@JvmSuppressWildcards Player>): Set<Player>
{
return players
}
@Provides
@IntoMap
@ClassKey(ErikTenHag::class)
//@StringKey("ErikTenHag")
fun providesManchester(@Named("ManchesterPlayers") players: Set<@JvmSuppressWildcards Player>): Set<Player> {
return players
}
}
interface Player {
fun name(): String
fun wages(): Double
fun position(): String
}
interface Manager {
fun name(): String
fun nationality(): String
}
class MohamedSalah @Inject constructor() : Player {
override fun name(): String = this::class.java.simpleName
override fun wages(): Double = 18200000.00
override fun position(): String = "Forward"
override fun toString(): String {
return "${name()} - ${wages()} - ${position()}"
}
}
class VirgilVanDyke @Inject constructor() : Player {
override fun name(): String = this::class.java.simpleName
override fun wages(): Double = 11440000.00
override fun position(): String = "Defender"
override fun toString(): String {
return "${name()} - ${wages()} - ${position()}"
}
}
class JurgenKlopp @Inject constructor() : Manager {
override fun name(): String = this::class.java.simpleName
override fun nationality(): String = "German"
}
class ErikTenHag @Inject constructor() : Manager {
override fun name(): String = this::class.java.simpleName
override fun nationality(): String = "Netherlands"
}
class CarlosCasimiro @Inject constructor() : Player {
override fun name(): String = this::class.java.simpleName
override fun wages(): Double = 118200000.00
override fun position(): String = "Midfield"
override fun toString(): String {
return "${name()} - ${wages()} - ${position()}"
}
}
class MasonMount @Inject constructor() : Player {
override fun name(): String = this::class.java.simpleName
override fun wages(): Double = 13000000.00
override fun position(): String = "Midfield"
override fun toString(): String {
return "${name()} - ${wages()} - ${position()}"
}
}
class HarryMaguire @Inject constructor() : Player {
override fun name(): String = this::class.java.simpleName
override fun wages(): Double = 1.50
override fun position(): String = "Defender"
override fun toString(): String {
return "${name()} - ${wages()} - ${position()}"
}
}
@JvmSuppressWildcards
data class FootballLeague @Inject constructor(val teamMap: Map<@JvmSuppressWildcards Class<*>, Set<Player>>) {
fun getFootballLeagueInstance() {
teamMap.entries.forEach {
println("xxooxx ${it.key} to ${it.value}")
}
}
}
首先,让我们解决问题的
KClass
/Class
部分。用 Kotlin 编写的注释总是使用 KClass
而不是 Class
,但这只是一个允许独立于 JVM 的语言概念。实际上,在构建 JVM 时,这些 KClass
参数/参数被编译为纯 Java Class
es。因此,Dagger 将它们视为 Class
并且对 KClass
一无所知。
现在关于
Class<*>
类型约束。是的,您可以限制 Class<>
内的类型。为此,您需要声明自定义@MapKey
关键注释,如下所示:
@dagger.MapKey
annotation class ManagerClassKey(
val value: KClass<out Manager>
)
然后使用这个新的
ManagerClassKey
代替 ClassKey
。