Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Properties 在Kotlin中访问属性委托_Properties_Delegates_Kotlin - Fatal编程技术网

Properties 在Kotlin中访问属性委托

Properties 在Kotlin中访问属性委托,properties,delegates,kotlin,Properties,Delegates,Kotlin,Kotlin具有委托属性,这是一个非常好的特性。但有时get()和set()方法是不够的。假设我想创建一个可关闭的对象,然后再关闭它。下面是如何实现此类委托属性的示例: fun <T : Closeable> closeableLazy(initializer: () -> T) = CloseableLazyVal(initializer) class CloseableLazyVal<T : Closeable>( private va

Kotlin具有委托属性,这是一个非常好的特性。但有时
get()
set()
方法是不够的。假设我想创建一个
可关闭的
对象,然后再关闭它。下面是如何实现此类委托属性的示例:

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

不幸的是,这种方法不起作用,因为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)
    }

}
在Kotlin 1.1中(自beta 2以来),可以从属性中检索委托,因此您现在可以编写

override fun close() {
    (::stream.apply { isAccessible = true }.getDelegate() 
        as CloseableLazyVal<*>).close()
}
override fun close(){
(::stream.apply{isAccessible=true}.getDelegate()
as CloseableLazyVal).close()
}

谢谢您的回答。您的解决方案很好,在这种特殊情况下解决了问题,但并非在所有情况下都有效。比方说,我想在不同的时刻关闭不同的
Closeable
对象。要处理这种情况,我必须向实现中添加一些键,以使
close()
更细粒度。在我看来,这种功能必须由语言本身提供,而不存在所有这些漏洞。我通常面临的另一个问题是,当我需要检查
Delegate.lazy
属性是否已初始化时。如果我们可以访问属性的委托,这个问题很容易解决,但是所有的遍历看起来都很难看。我意识到,您可以将委托声明为单独的属性,然后将第二个属性委托给它。通过这种方式,您可以轻松访问委托本身。这是一个有趣的解决方法。在这种情况下,我将不得不委托类中具有相同值的字段,因为这似乎是一个可行的解决方案。在将这些功能添加到语言核心之前,您的解决方案可能是实现我想要的功能的最佳方式。只需使用value?.close()@cypressious,你说得对,谢谢。不过需要kotlin reflect库
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()
}
override fun close() {
    (::stream.apply { isAccessible = true }.getDelegate() 
        as CloseableLazyVal<*>).close()
}