首页 文章

我如何获得Kotlin酒店的名称?

提问于
浏览
6

我有以下功能来访问属性的委托 . 它使用Kotlin反射获取属性的名称和Java反射来获取字段 .

fun Any.getDelegate<T>(prop: KProperty<T>): Any {
    return javaClass.getDeclaredField("${prop.name}\$delegate").let {
        it.setAccessible(true)
        it.get(this)
    }
}

该方法使用如下:

val delegate = a.getDelegate(A::b)

但是,我更喜欢这样使用它:

val delegate = a.b.delegate

上面代码的问题是获取 a.b 的属性名称并从 a.b 获取实例 a . 根据我对Kotlin的了解,这可能是不可能的,但是我想看看我是否可以清理我的功能 .

为了更好地了解我正在尝试做的事情,这是我的完整代码 . 我想要一个可观察的委托,我可以使用委托引用添加和删除观察者,而无需创建添加变量 .

fun Any.addObservable<T>(prop: KProperty<T>, observer: (T) -> Unit) {
    getObservableProperty(prop).observers.add(observer)
}

fun Any.getObservableProperty<T>(prop: KProperty<T>): ObservableProperty<T> {
    return getDelegate(prop) as ObservableProperty<T>
}

fun Any.getDelegate<T>(prop: KProperty<T>): Any {
    return javaClass.getDeclaredField("${prop.name}\$delegate").let {
        it.setAccessible(true)
        it.get(this)
    }
}

class ObservableProperty<T>(
        initialValue: T,
        initialObservers: Array<(T) -> Unit> = emptyArray()) : ReadWriteProperty<Any?, T> {

    private var value = initialValue

    public val observers: MutableSet<(T) -> Unit> = initialObservers.toHashSet()

    public override fun get(thisRef: Any?, desc: PropertyMetadata): T {
        return value
    }

    public override fun set(thisRef: Any?, desc: PropertyMetadata, value: T) {
        this.value = value
        observers.forEach { it(value) }
    }
}

class A() {
    var b by ObservableProperty(0)
}

fun main(args: Array<String>) {
    val a = A()

    a.addObservable(A::b) {
        println("b is now $it")
    }

    a.b = 1
    a.b = 2
    a.b = 3
}

编辑:

我刚刚意识到该函数也不严格,因为属性委托字段名称由 KProperty name引用,这不是一个示例来演示问题:

class A() {
    var foo by ObservableProperty(0)
}

class B() {
    var foo by ObservableProperty(0)
}

fun main(args: Array<String>) {
    val a = A()

    a.addObservable(B::foo) {
        println("b is now $it")
    }

    a.foo = 1
    a.foo = 2
    a.foo = 3
}

这会编译并运行而不会出错,因为 A::fooB::foo 都会产生 "foo$delegate 的字段字符串 .

2 回答

  • 1

    现在反射就是我们可以做的所有事情来获取委托对象 . 我们正在设计一种语言功能,可以直接访问委托实例,但这还有很长的路要走 .

  • 3

    这就是你如何获得Kotlin Property的名称(尽管只有一个类的实例) . 这个部分对于任何纯粹基于其 Headers 的人来说都是有用的 .

    class Stuff(val thing: String)
    
    val stuff = Stuff("cool stuff")
    val thingFieldName = "${stuff.thing}\$delegate"
    // value of thingFieldName is now "thing"
    

    在让代表本身更容易方面,他们说你现在可以这样做:

    class Foo {
        var bar: String by ReactiveProperty<String>()
    }
    
    val foo = Foo()
    val bar = foo.bar
    val barDelegate = ... // foo.bar$delegate
    

    See ticket.

相关问题