在 Kotlin 中访问 属性 委托
Access property delegate in Kotlin
Kotlin 具有委托属性,这是一个非常好的功能。但有时 get()
和 set()
方法是不够的。假设我想延迟创建一个 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
。为了简化实现,我将这个接口委托给一个简单的基于列表的实现。
UPDATE(从评论中复制):
我意识到,您可以将委托声明为单独的 属性,然后将第二个 属性 委托给它。这样您就可以轻松访问委托本身。
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()
}
Kotlin 具有委托属性,这是一个非常好的功能。但有时 get()
和 set()
方法是不够的。假设我想延迟创建一个 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
。为了简化实现,我将这个接口委托给一个简单的基于列表的实现。
UPDATE(从评论中复制): 我意识到,您可以将委托声明为单独的 属性,然后将第二个 属性 委托给它。这样您就可以轻松访问委托本身。
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()
}