首页 > 解决方案 > 这在 kotlin 接口委托中

问题描述

this使用接口委托时有什么方法可以通过吗?这将实现很好的可组合性——但我发现没有办法做到这一点。意味着类似:

interface Foo {
}

class FooImpl(bar: Bar) : Foo {

}

class Bar: Foo by FooImpl(this) {
}

只要 FooImpl 不需要这样的参数,它就可以工作-但是访问那里的另一个类会很棒-也许有人知道一种方法。否则,我也会感兴趣,如果不值得 KEEP - 或者由于某种原因这将是不可能的。

标签: kotlininterfacedelegation

解决方案


委托不支持这一点。委托必须在委托给它的类之前实例化,因此委托不能依赖它进行构造。另一个问题是,尽管您可以覆盖委托的函数,但如果委托在内部调用这些函数,它将调用原始版本,而不是覆盖。代表真的活在自己的世界里。

但是您可以将其设置为主机在其初始化块中将自身传递给委托:

interface Foo<T> {
    var host: T
    fun doSomething()
}

class FooImpl : Foo<Bar> {
    override lateinit var host: Bar

    override fun doSomething() {
        println(host.name)
    }
}

class Bar(val name: String): Foo<Bar> by FooImpl() {
    init {
        host = this
    }
}

fun main() {
    val bar = Bar("Hello world")
    bar.doSomething()
}

不幸的是,这会使主机暴露于外部类与其自己的委托断开连接的可能性。如果多次分配,也许您可​​以使该属性引发异常。

这是一个可以做到这一点的属性委托:

private class SingleAssignmentVar<T>: ReadWriteProperty<Any, T> {
    private var value: T? = null
    private var assigned: Boolean = false

    @Suppress("UNCHECKED_CAST")
    override fun getValue(thisRef: Any, property: KProperty<*>): T {
        if (!assigned)
            error("Property has not yet been set.")
        return value as T
    }

    override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
        if (assigned)
            error("Property may only be set once.")
        assigned = true
        this.value = value
    }
}

fun <T> Delegates.singleAssignment(): ReadWriteProperty<Any, T> = SingleAssignmentVar()

推荐阅读