访问Kotlin的财产代表

Kotlin已经委派了属性,这是一个非常好的功能。 但有时get()set()方法是不够的。 假设我想要Closeable地创建一个Closeable对象并稍后关闭它。 下面是一个如何实现这样的委托属性的例子:

 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() } } 

这就是我想要使用它的方式:

 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添加这样的功能,因为它会是一个很好的功能。

好的,所以我想出了以下解决方案:

 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继承,它将在关闭时关闭所有已注册的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() }