Kotlin:我怎样才能得到一个成员财产的代表团类?
我怎样才能得到一个成员属性的委托类?
通过这个,我的意思是有可能完成这样一个功能:
inline fun <reified T> delegationExample(t: T) { for (prop in T::class.declaredMemberProperties) { val delegatedClass = // what to do?! } }
代表团可能看起来像这样:
class DelegationExample { operator fun getValue(ref: Any, prop: KProperty<*>) = 0 }
而声明类可能是这样的:
object Example { val a by DelegationExample() val b by DelegationExample() val c by DelegationExample() }
要找到委托给委托类的属性以及该类的实例,下面是一个实用程序函数:
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,并且可以为空,所以它被保存到一个局部变量中,所以智能转换将在以后工作。 - 然后,如果此字段与您正在查找的委托类具有相同的类型,则可以访问该字段。
- 但首先你必须强制该领域的可访问性,因为它是一个
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]
在字节代码级别上,委托属性不会延迟常规(public getter / setter和private字段)。
你可以去的一个方法是扫描Example
的私有字段,并过滤那些具有operator getValue(thisRef: R, KProperty<*>)
。 从技术上讲,一个字段可能包含一个委托对象val x = lazy {1}
,但这不太可能。