访问Kotlin的财产代表
Kotlin已经委派了属性,这是一个非常好的function。 但有时get()
和set()
方法是不够的。 假设我想要Closeable
地创建一个Closeable
对象并稍后关闭它。 下面是一个如何实现这样的委托属性的例子:
fun closeableLazy(initializer: () -> T) = CloseableLazyVal(initializer) class CloseableLazyVal( private val initializer: () -> T ) : ReadOnlyProperty { private var value: T? = null override fun get(thisRef: Any?, desc: PropertyMetadata): T { if (value == null) { value = initializer() } return value } fun close() { value?.close() } }
这就是我想要使用它的方式:
private val stream by closeableLazy { FileOutputStream("/path/to/file") } fun writeBytes(bytes: ByteArray) { stream.write(bytes) } override fun close() { stream::delegate.close() // This line will not compile }
不幸的是,这种方法不起作用,因为Kotlin似乎不允许直接访问财产代表。 有什么办法可以做我想要的吗? 或者有没有计划为Kotlin添加这样的function,因为它会是一个很好的function。
好的,所以我想出了以下解决方案:
fun closeableLazy(initializer: () -> T) = CloseableLazyVal(initializer) class CloseableLazyVal ( private val initializer: () -> T ) : ReadOnlyProperty { private var value: T? = null override fun get(thisRef: CloseableDelegateHost, desc: PropertyMetadata): T { if (value == null) { value = initializer() thisRef.registerCloseable(value!!) } return value!! } } interface CloseableDelegateHost : Closeable { fun registerCloseable(prop : Closeable) } class ClosableDelegateHostImpl : CloseableDelegateHost { val closeables = arrayListOf() override fun registerCloseable(prop: Closeable) { closeables.add(prop) } override fun close() = closeables.forEach { it.close() } } class Foo : CloseableDelegateHost by ClosableDelegateHostImpl() { private val stream by closeableLazy { FileOutputStream("/path/to/file") } fun writeBytes(bytes: ByteArray) { stream.write(bytes) } }
注意,属性的get方法有一个参数thisRef
。 我要求它从CloseableDelegateHost
inheritance,它将在关闭时关闭所有已注册的Closeable
。 为了简化实现,我将这个接口委托给一个简单的基于列表的实现。
更新 (从评论复制):我意识到,你可以声明委托作为一个单独的属性,然后委托第二个属性。 这样,您可以轻松访问委托。
private val streamDelegate = closeableLazy { FileOutputStream("/path/to/file") } private val stream by streamDelegate fun writeBytes(bytes: ByteArray) { stream.write(bytes) } override fun close() { streamDelegate.close() }
在Kotlin 1.1(自beta 2以来),代表可以从属性中检索,所以你现在可以写
override fun close() { (::stream.apply { isAccessible = true }.getDelegate() as CloseableLazyVal<*>).close() }