我怎样才能得到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 = abdelegate 

上面代码的问题是获取ab的属性名称并从ab获取实例。 根据我对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") } ab = 1 ab = 2 ab = 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 

    看票。