Kotlin ReadWriteProperty:无法使用“T”作为具体化类型参数。使用类来代替

问题描述 投票:0回答:1

由于我对仿制药还不太擅长,所以我想问:

错误

Cannot use 'T' as reified type parameter. Use a class instead

我错过了什么?

enumValueOf()
不工作...

class EnumSharedPreferenceProperty<T : Enum<T>>(
    private val pref: SharedPreferences,
    private val name: String,
) : ReadWriteProperty<Any, T> {


    override fun getValue(thisRef: Any, property: KProperty<*>): T {
        val enumName = pref.getString(name, "").orEmpty()
        return enumValueOf(enumName)
    }

    override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
        pref.edit().putString(name, value.name).commit()
    }
}
java android kotlin
1个回答
0
投票

当执行此操作的类型不可用时,您尝试使用具体化类型参数调用 Kotlin 函数。这不会编译,你需要另一种方法。

具体化类型参数

这是 Kotlin 的一项功能,编译器使用内联函数跟踪具体(“具体化”)类型,从而产生更优雅的 API 并减少反射的使用。但是,如果您无权访问调用站点的具体类,而只有变量内的目标类(或者,如您的示例所示,根本没有类),则无法调用这样的函数。

因此,这样的调用是可能的:

enum class MyEnum { ONE, TWO }

fun main() {
    println(enumValueOf<MyEnum>("ONE"))
}

这里我具体访问到了

MyEnum
,所以调用成功了。

你的例子

在您的示例中,似乎不可能获得具体的枚举类。这是因为这样做涉及函数内联,但在 Kotlin 中无法使用纯粹具体化的类型参数实例化类。另一方面,为了让您提议的委托工作,您必须使用一个类来执行委托。

使用 JVM 上的反射访问枚举值

不过,如果您在 JVM 上工作,有一种方法可以实现您想要的目标,即使用 Java 反射1

首先,您需要在类的构造函数中以某种方式捕获枚举类实例2

class EnumSharedPreferenceProperty<T : Enum<T>>(
    private val enumClass: KClass<T>,
    // ...
)

然后您可以使用或改编以下函数,该函数使用 Java 反射来获取枚举实例3

fun <E : Enum<*>> enumValueOf(name: String, enumClass: KClass<E>): E {
    return enumClass.java.enumConstants
        ?.singleOrNull { eachEnumValue -> eachEnumValue.name == name }
        ?: error("No enum of value $name found in class $enumClass")
}

并按如下方式调用它,而不是常规的

enumValueOf
函数:

return enumValueOf(enumName, enumClass)

1如果您在多个或其他平台上工作,如果您足够渴望让这种方法发挥作用,也可能有一种方法可以在这些平台上重现此类功能

2有趣的是,使用带有具体化类型参数的内联函数可能是一种优雅的方法,并在设置委托属性时调用它,但这可能有点超出了问题的范围

3我在Kotlin Playground

上写了这个函数的一些测试/证明
© www.soinside.com 2019 - 2024. All rights reserved.