如何获取Kotlin房产的名称



我有以下函数来访问属性的委托。它使用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名称引用,这不需要对封闭类的强引用。这里有一个例子来说明这个问题:

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的字段字符串,因此编译和运行时不会出现错误。

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

这就是获取Kotlin属性名称的方法(尽管仅使用该类的实例(。这一部分对任何纯粹根据标题来回答这个问题的人都很有用。

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

请参阅票证。

相关内容

  • 没有找到相关文章

最新更新