Это возможно, но требует небольшой работы и небольшого структурного изменения в том, как работает наблюдаемый делегат.
Сначала создайте класс для хранения состояния при изменении, это позволит вам также добавить в этот класс свою инфиксную функцию:
data class StateChange<T>(val property: KProperty<*>, val oldValue: T, val newValue: T) {
infix fun State.into(s: State): Boolean {
return this == oldValue && s == newValue
}
}
Теперь создайте новую функцию-делегат, которая будетсоздайте делегат и вместо вызова лямбда-функции со всеми значениями в качестве параметра будет ожидать лямбда, являющуюся методом расширения класса StateChange
.Поэтому эта лямбда также будет иметь доступ к своим свойствам и функциям.
inline fun <T> observableState(initialValue: T, crossinline onChange: StateChange<T>.() -> Unit):
ReadWriteProperty<Any?, T> =
object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
with (StateChange(property, oldValue, newValue)) { onChange() }
}
}
Теперь используйте ее где угодно, и ваша инфиксная функция будет доступна:
var state: State by observableState(START) {
// property, oldValue, and newValue are all here on this object!
when {
START into STOP -> { // works!
doSomeMagic(newValue) // example accessing the newValue
}
}
}
Обратите внимание на немного другоеСинтаксис, который вы используете для передачи лямбда-функции в функцию observableState
, более идиоматичен, чтобы не объявлять полный заголовок функции, а вместо этого просто иметь лямбда-тело со всем выводом.Теперь все равно нет параметров.
Стоимость этого - новое выделение небольшого класса данных каждый раз, когда происходит событие.