如何获取 Kotlin 属性 的名称?
How can I get the name of a Kotlin property?
我有以下函数来访问 属性 的委托。它使用 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
名称引用,不需要对封闭的 [=45] 的强引用=].这是一个演示问题的示例:
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::foo
和 B::foo
都导致字段字符串 "foo$delegate
.
现在我们只能通过反射来获取委托对象。我们正在设计一种语言功能来直接访问委托实例,但这还有很长的路要走。
这就是您如何获得 Kotlin 属性 的名称(尽管只有 class 的一个实例)。这部分对任何纯粹根据标题得出这个问题的人都有用。
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
我有以下函数来访问 属性 的委托。它使用 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
名称引用,不需要对封闭的 [=45] 的强引用=].这是一个演示问题的示例:
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::foo
和 B::foo
都导致字段字符串 "foo$delegate
.
现在我们只能通过反射来获取委托对象。我们正在设计一种语言功能来直接访问委托实例,但这还有很长的路要走。
这就是您如何获得 Kotlin 属性 的名称(尽管只有 class 的一个实例)。这部分对任何纯粹根据标题得出这个问题的人都有用。
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