Kotlin:如何获得成员 属性 的委托 class?

Kotlin: How can I get the delegation class of a member property?

如何获得成员 属性 的授权 class?

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

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

代表团 class 可能看起来像:

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

声明 class 可能如下所示:

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

在字节码级别上,委托属性不会延迟常规属性(public getter/setter 和私有字段)。

您可以采用的一种方法是扫描 Example 的私有字段并过滤具有 operator getValue(thisRef: R, KProperty<*>) 的私有字段。从技术上讲,一个字段可能包含一个委托对象 val x = lazy {1},但这不太可能。

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

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()
}

一些注意事项:

  • 首先将您的具体化类型 T 更正为 T: Any 否则您无法访问 Kotlin 反射中的所有扩展,包括 declaredMemberProperties
  • 最简单的方法是从 属性 参考文献进入该领域,以确保您实际上谈论的是真正的 属性,因此对于每个 declaredMemberProperties 使用javaField 这样做。
  • 由于 javaField 是自定义的 getter 并且可以为 null,因此它被保存到一个局部变量中,以便稍后进行智能转换。
  • 然后如果此字段与您要查找的委派 class 具有相同类型,则您可以访问该字段。
  • 但首先您必须强制该字段的可访问性,因为它是一个 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}]")
    }
}

输出类似于:

property 'a' delegates to instance of [DelegationExample@2c1b194a]
property 'b' delegates to instance of [DelegationExample@4dbb42b7]
property 'c' delegates to instance of [DelegationExample@66f57048]

避免反射的一种方法是首先初始化您的委托对象并将其存储为它自己的成员,然后由它委托您的 属性。

object Example {
    val aDelegate = DelegationExample()
    val bDelegate = DelegationExample()
    val cDelegate = DelegationExample()

    val a by aDelegate
    val b by bDelegate
    val c by cDelegate
}