访问科特林的财产代表 [英] Access property delegate in Kotlin

查看:98
本文介绍了访问科特林的财产代表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

这篇关于访问科特林的财产代表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆