问题描述
Kotlin具有委派的属性,这是一个非常不错的功能.但是有时候get()
和set()
方法是不够的.假设我要延迟创建Closeable
对象,然后稍后将其关闭.这是一个如何实现此类委托属性的示例:
Kotlin has delegated properties which is a very nice feature. But sometimes get()
and set()
methods are not enough. Let's say I want to create a Closeable
object lazily and to close it later. Here's an example of how such delegate property could be implemented:
fun <T : Closeable> closeableLazy(initializer: () -> T) =
CloseableLazyVal(initializer)
class CloseableLazyVal<T : Closeable>(
private val initializer: () -> T
) : ReadOnlyProperty<Any?, T> {
private var value: T? = null
override fun get(thisRef: Any?, desc: PropertyMetadata): T {
if (value == null) {
value = initializer()
}
return value
}
fun close() {
value?.close()
}
}
这就是我想使用它的方式:
And that's how I would like to use it:
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添加此类功能,因为这将是一个如此巧妙的功能.
Unfortunately, this approach doesn't work because it seems that Kotlin doesn't allow to access property delegates directly. Is there any way to do what I want? Or are there any plans to add such functionality to Kotlin because it would be such a neat feature.
推荐答案
好,所以我提出了以下解决方案:
Ok, so I came up with the following solution:
fun <T : Closeable> closeableLazy(initializer: () -> T) =
CloseableLazyVal(initializer)
class CloseableLazyVal<T : Closeable>(
private val initializer: () -> T
) : ReadOnlyProperty<CloseableDelegateHost, T> {
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<Closeable>()
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
继承,而CloseableDelegateHost
在关闭时将关闭所有已注册的Closeable
.为了简化实现,我将此接口委托给基于列表的简单实现.
Notice, that the property's get method has a parameter thisRef
. I require that it inherits from CloseableDelegateHost
which will close any registered Closeable
s when it is closed. To simplify the implementation I delegate this interface to a simple list-based implementation.
更新(摘自评论):我意识到,您可以只将委托声明为单独的属性,然后将第二个属性委托给它.这样,您可以轻松访问委托本身.
UPDATE (copied from comments):I realized, you can just declare the delegate as a separate property and then delegate the second property to it. This way you can access the delegate itself easily.
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()
}
这篇关于访问科特林的财产代表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!