在委托属性上使用上下文接收器



我有一个使用上下文接收器的属性委托:

class LoggingPropertyDelegate<T, V, L : Log>(
private var value: V,
private val toLog: T.() -> L
) : ReadWriteProperty<T, V> {
override fun getValue(thisRef: T, property: KProperty<*>) = value
context(Logger)
override fun setValue(thisRef: T, property: KProperty<*>, value: V) {
this.value = value
log(toLog(thisRef))
}
}

但是当我尝试在属性上使用它时:

var myValue: Int by LoggingPropertyDelegate(0, { InfoLog("Changed to $myValue") })

我得到一个错误,没有合适的set函数的委托。如果我从方法中删除上下文,一切都按预期工作。

不能在属性委托上使用上下文接收器吗?

可以使用具有上下文接收者的属性委托。您只需要以某种方式提供上下文接收器。

首先,注意您应该将context(Logger)放在委托类类型上,而不是放在setValue上:

context(Logger)
class LoggingPropertyDelegate<T, V, L : Log>(

如果myValue是某个类Foo的实例属性,那么您可以这样做:

context(Logger)
class Foo {
var myValue: Int by LoggingPropertyDelegate(0) { ... }
}

注意,如果Foo是一个数据类,那么似乎存在导致编译器崩溃的编译器错误。也许上下文接收器被降低到额外的编译器参数(?)

然后在实例化Foo时,您需要提供Logger:

val foo = with(someLogger) { Foo() }
// now you can access foo.myValue

(或者用Logger上下文接收器在另一个函数中实例化Foo)

如果myValue是一个局部变量,除了在封闭函数中添加Logger上下文接收者之外,还可以直接使用with来引入上下文接收者实例。

最新更新