由于我对仿制药还不太擅长,所以我想问:
错误
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()
}
}
当执行此操作的类型不可用时,您尝试使用具体化类型参数调用 Kotlin 函数。这不会编译,你需要另一种方法。
这是 Kotlin 的一项功能,编译器使用内联函数跟踪具体(“具体化”)类型,从而产生更优雅的 API 并减少反射的使用。但是,如果您无权访问调用站点的具体类,而只有变量内的目标类(或者,如您的示例所示,根本没有类),则无法调用这样的函数。
因此,这样的调用是可能的:
enum class MyEnum { ONE, TWO }
fun main() {
println(enumValueOf<MyEnum>("ONE"))
}
这里我具体访问到了
MyEnum
,所以调用成功了。
在您的示例中,似乎不可能获得具体的枚举类。这是因为这样做涉及函数内联,但在 Kotlin 中无法使用纯粹具体化的类型参数实例化类。另一方面,为了让您提议的委托工作,您必须使用一个类来执行委托。
不过,如果您在 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有趣的是,使用带有具体化类型参数的内联函数可能是一种优雅的方法,并在设置委托属性时调用它,但这可能有点超出了问题的范围
上写了这个函数的一些测试/证明