Kotlin惯用的方式来转发不同类别的财产

时间:2019-04-13 12:15:30

标签: generics kotlin reflection delegates

例如:

class A {    
    var value: String
    get() = "value"
    set(value) { println(value) }
}

class B {
    val a = A()
    var value = a.value
}

fun main(args: Array<String>) {
    B().value = "new value"
}

B.value仅用A.value.get初始化,因此在A.value.set函数中分配期间当然不会调用main,因此不会将消息打印到控制台。

我要寻找的是一种语法,该语法将允许根据相同类型的不同对象的属性将getset函数转发到新变量。

我设法实现了这种委托,但是它依赖于kotlin-reflect库(调用gettersetter),我想避免这种情况:

import kotlin.reflect.KProperty
import kotlin.reflect.KMutableProperty

class Forward<T> (private val originalProperty: KProperty<T>){
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return originalProperty.getter.call()
    }
}

class ForwardMutable<T> (private val originalProperty: KMutableProperty<T>){
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        originalProperty.setter.call(value)
    }

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return originalProperty.getter.call()
    }
}

fun <T> forward(originalProperty: KProperty<T>) = Forward(originalProperty)
fun <T> forward(originalProperty: KMutableProperty<T>) = ForwardMutable(originalProperty)

class A {
    var value: String
        get() = "value"
        set(value) { println(value) }
}

class B {
    val a = A()
    var value by forward(a::value)
}

fun main(args: Array<String>) {
    B().value = "new value" // calls A.value.setter
}

是否没有用于此目的的内置委托?如果没有,如何避免kotlin-reflect依赖性?

2 个答案:

答案 0 :(得分:0)

如果thisRef必须与Any一样通用,那么我认为您不能在没有反射的情况下访问其属性。

如果您愿意引入其他接口,则可以按照以下方式做一些事情:(kotlin.reflect仍然有导入依赖项,但是Delegate API要求这样做)

import kotlin.reflect.KProperty

interface HasA<T> {
    val a: ValueAccessor<T>
}

interface ValueAccessor<T> {
    var value: T
}

class ForwardMutable<T> {
    operator fun setValue(thisRef: HasA<T>, property: KProperty<*>, value: T) {
        thisRef.a.value = value
    }

    operator fun getValue(thisRef: HasA<T>, property: KProperty<*>): T {
        return thisRef.a.value
    }
}

class A : ValueAccessor<String> {
    override var value: String = "value"
}

class B : HasA<String> {
    override val a = A()
    var value by ForwardMutable<String>()
}

fun main(args: Array<String>) {
    val b = B()
    b.value = "new value" // calls A.value.setter
    print(b.value)
}

答案 1 :(得分:0)

也许我误会了一些东西,但是,如果您能够提取要委托给内部实例的变量的接口,那为什么不只使用委托呢?

interface SomethingWithValues{
    var value: String
    var value2: String
    var value3: String
}

class A : SomethingWithValues{
    override var value: String = "value"
        set(value) {print(value)}
    override var value2: String = "value2"
        set(value) {print(value)}
    override var value3: String = "value3"
        set(value) {print(value)}
}

class B(val a:A = A()): SomethingWithValues by a

fun main(args: Array<String>) {
    val b = B()
    b.value = "new value"
    b.value2 = "new value2"
    b.value3 = "new value3"
}