Как сделать так, чтобы делегат применялся ко всем свойствам в классе? - PullRequest
0 голосов
/ 11 июля 2020

У меня есть класс A, который необходимо пометить как dirty каждый раз, когда изменяется одно из его свойств.

После просмотра документов Kotlin я знаю, что мне нужен делегат. Пока у меня есть:


abstract class CanBeDirty {
    var isDirty = false
}
class A(
// properties getting set in constructor here
) : CanBeDirty {
var property1: String by DirtyDelegate()
var property2: Int by DirtyDelegate()
var property3: CustomObject by DirtyDelegate()

}
class DirtyDelegate() {
    operator fun getValue(thisRef: CanBeDirty, property: KProperty<*>): Resource {
        return valueOfTheProperty
    }
    operator fun setValue(thisRef: CanBeDirty, property: KProperty<*>, value: Any?) {
        if (property != value) {
            thisRef.isDirty = true
            //set the value
        }
        else {
            //don't set the value
        }
    }

}

Я считаю, что отсутствие настроек как-то связано с vetoable(), но примеры, которые я вижу в документации Kotlin, мне не показывают как это сделать с полностью сформированным делегатом класса (и, честно говоря, я просто не в курсе синтаксиса Kotlin).

1 Ответ

3 голосов
/ 11 июля 2020

Вашему классу делегата требуется собственное свойство для хранения возвращаемого значения. И если вы не хотите иметь дело с неинициализированными значениями, он также должен иметь параметр конструктора для начального значения. Вам не нужно реализовывать ReadWriteProperty, но он позволяет IDE автоматически генерировать правильную подпись для двух операторных функций.

class DirtyDelegate<T>(initialValue: T): ReadWriteProperty<CanBeDirty, T> {
    private var _value = initialValue

    override fun getValue(thisRef: CanBeDirty, property: KProperty<*>): T {
        return _value
    }

    override fun setValue(thisRef: CanBeDirty, property: KProperty<*>, value: T) {
        if (_value != value) {
            _value = value
            thisRef.isDirty = true
        }
    }
}

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

class A: CanBeDirty() {
    var property1: String by DirtyDelegate("")
    var property2: Int by DirtyDelegate(0)
    var property3: CustomObject by DirtyDelegate(CustomObject())
}

Если вы хотите установить начальное значение на основе чего-то, переданного конструктору, вы можете сделать:

class B(initialName: String): CanBeDirty() {
    var name by DirtyDelegate(initialName)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...