我有一个使用上下文接收器的属性委托:
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
来引入上下文接收者实例。