考虑我正在尝试实现delegation by storing properties in a Map
instance,并且委派的属性之一是数组:
class Foo private constructor(map: Map<String, Any?>) {
constructor(value: Array<Byte>) : this(mapOf(Foo::value.name to value))
val value: Array<Byte> by map
}
object PropertyDelegationTest {
@JvmStatic
fun main(vararg args: String) {
val foo = Foo(arrayOf(42.toByte(), 127.toByte()))
println(foo.value[0]) // 42
println(foo.value[1]) // 127
}
}
上面的代码编译得很好,并且可以按预期工作。
现在考虑,我想通过实现自定义Map.getValue(thisRef: Any?, property: KProperty<*>)
扩展方法(覆盖default extension)来增强我的属性委派机制:
import kotlin.reflect.KProperty
import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.full.starProjectedType
import kotlin.reflect.jvm.jvmName
// ...
operator fun <V, V1 : V> Map<in String, V>.getValue(thisRef: Any?, property: KProperty<*>): V1 {
val value = this[property.name]
?: throw NoSuchElementException("Key ${property.name} is missing in the map.")
val clazz = (value as Any)::class
@Suppress("UNCHECKED_CAST")
return when {
clazz.starProjectedType.isSubtypeOf(property.returnType) -> value as V1
else -> throw ClassCastException("${clazz.starProjectedType} (${clazz.jvmName}) cannot be cast to ${property.returnType}")
}
}
这在运行时失败:
Exception in thread "main" java.lang.ClassCastException: kotlin.Array<*> ([Ljava.lang.Byte;) cannot be cast to kotlin.Array<kotlin.Byte>
at com.example.PropertyDelegationTestKt.getValue(PropertyDelegationTest.kt:30)
at com.example.Foo.getValue(PropertyDelegationTest.kt)
at com.example.PropertyDelegationTest.main(PropertyDelegationTest.kt:18)
尽管已知有效的JVM类型([Ljava.lang.Byte;
),但Kotlin特定于运行时的值是Array<*>
,而Array<Byte>
是必需的。一致地,clazz.typeParameters[0].upperBounds[0]
的计算结果为kotlin.Any?
,不是 kotlin.Byte?
。
如何实现我的自定义类型检查,该检查对于数组也可以正常工作? Kotlin版本是1.2.71。
答案 0 :(得分:1)
您可以删除显式类型检查,而是安全地转换为V1
,如果失败,则抛出异常,例如
return value as? V1 ?: throw ClassCastException(...