Пользовательское делегирование свойств для массивов с использованием карты - PullRequest
0 голосов
/ 20 ноября 2018

Учтите, что я пытаюсь реализовать делегирование , сохраняя свойства в Map экземпляре , и одним из делегированных свойств является массив:

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<*>) (переопределяя расширение по умолчанию ):

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?.

Как мне реализовать свою пользовательскую проверку типов, которая также будет корректно работать для массивов?Котлин версия 1.2.71.

1 Ответ

0 голосов
/ 21 ноября 2018

Вы можете удалить явную проверку типа и вместо этого выполнить безопасное приведение к V1, а если это не удастся, то выдать исключение, например,

return value as? V1 ?: throw ClassCastException(... 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...