如何实现从某个源获取的属性,直到它直接在Kotlin中设置?

时间:2017-04-16 13:39:36

标签: properties kotlin

我目前有一个声明如下的属性:

class Foo(val base : FooBase){
    var _number: Int? = null

    override var number: Int
        get() = _number ?: base.number
        set(value) {_number = value}
}

但是,我有很多这样的属性,导致相当多的代码重复。有办法避免这种情况吗?我理解属性委派是一种方法,但我不确定如何正确实现ReadWriteProperty<...>。如果我应该使用它,我如何使用“属性”值?

2 个答案:

答案 0 :(得分:6)

您需要创建一个扩展ReadWriteProperty的类来提供功能(代码示例基于不安全的延迟实现)

class UninitializedProperty<T>(private val getter: () -> T) : ReadWriteProperty<Any?, T> {
    var _value: Any? = UNINITIALIZED_VALUE

    @Suppress("UNCHECKED_CAST")
    override fun getValue(thisRef: Any?, property: KProperty<*>): T = if(_value === UNINITIALIZED_VALUE) getter() else _value as T

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        _value = value
    }

   private object UNINITIALIZED_VALUE
}

接下来,定义一个辅助方法,以保持与lazy等标准委托的一致性:

fun <T> uninitialized(getter: () -> T): ReadWriteProperty<Any?, T> = UninitializedProperty(getter)

现在你可以使用它了:

class Foo(val base: FooBase) {
    override var number: Int by uninitialized { base.number }
}

注意:该类不是线程安全的。

检查official documentation以获取有关委派的更多信息。

答案 1 :(得分:2)

这是对Yoav Sternberg的答案的表现改进。如你所见,它不那么通用,但它避免了自动装箱:

class IntUninitializedProperty(private val getter: () -> Int) {
    private var isInitialised = false
    private var value: Int = 0

    fun getValue(thisRef: Any?, property: KProperty<*>): Int = if(isInitialised) value else getter()

    fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
        this.value = value
        isInitialised = true
    }
}