Kotlin:如何获取成员属性的委托类?

Jir*_*ire 5 delegates properties delegation member kotlin

如何获取会员财产的委托类别?

我的意思是是否可以完成这样的功能:

inline fun <reified T> delegationExample(t: T) {
    for (prop in T::class.declaredMemberProperties) {
        val delegatedClass = // what to do?!
    }
}
Run Code Online (Sandbox Code Playgroud)

委托类可能如下所示:

class DelegationExample {
    operator fun getValue(ref: Any, prop: KProperty<*>) = 0
}
Run Code Online (Sandbox Code Playgroud)

声明类可能如下所示:

object Example {
    val a by DelegationExample()
    val b by DelegationExample()
    val c by DelegationExample()
}
Run Code Online (Sandbox Code Playgroud)

Jay*_*ard 4

要查找委托给委托类的属性以及该类的实例,这里有一个实用函数:

data class DelegatedProperty<T : Any, DELEGATE : Any>(val property: KProperty1<T, *>, val delegatingToInstance: DELEGATE)

inline fun <reified T : Any, DELEGATE : Any> findDelegatingPropertyInstances(instance: T, delegatingTo: KClass<DELEGATE>): List<DelegatedProperty<T, DELEGATE>> {
    return T::class.declaredMemberProperties.map { prop ->
        val javaField = prop.javaField
        if (javaField != null && delegatingTo.java.isAssignableFrom(javaField.type)) {
            javaField.isAccessible = true // is private, have to open that up
            @Suppress("UNCHECKED_CAST")
            val delegateInstance = javaField.get(instance) as DELEGATE
            DelegatedProperty(prop, delegateInstance)
        } else {
            null
        }
    }.filterNotNull()
}
Run Code Online (Sandbox Code Playgroud)

一些注意事项:

  • 首先将您的具体化类型更正T为,T: Any否则您将无法访问 Kotlin 反射中的所有扩展,包括declaredMemberProperties
  • 最简单的方法是从属性引用中访问该字段,以确保您实际上谈论的是真正的属性,因此每次declaredMemberProperties使用时javaField都这样做。
  • 由于javaField是一个自定义 getter 并且可以为空,因此它被保存到本地变量中,以便智能转换稍后可以使用。
  • 然后,如果该字段与您要查找的委托类具有相同的类型,则您可以访问该字段。
  • 但首先您必须强制该字段的可访问性,因为它是一个private字段。

在测试程序中运行:

class DelegationExample {
    operator fun getValue(ref: Any, prop: KProperty<*>) = 0
}

class Example {
    val a by DelegationExample()
    val b by DelegationExample()
    val c by DelegationExample()
}

fun main(args: Array<String>) {
    findDelegatingPropertyInstances(Example(), DelegationExample::class).forEach {
        println("property '${it.property.name}' delegates to instance of [${it.delegatingToInstance}]")
    }
}
Run Code Online (Sandbox Code Playgroud)

输出类似于:

property 'a' delegates to instance of [DelegationExample@2c1b194a]
property 'b' delegates to instance of [DelegationExample@4dbb42b7]
property 'c' delegates to instance of [DelegationExample@66f57048]
Run Code Online (Sandbox Code Playgroud)