Kotlin: ¿Cómo puedo get la class de delegación de una propiedad miembro?

¿Cómo puedo get la class de delegación de una propiedad miembro?

Con esto, quiero decir que es posible completar dicha function:

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

Donde se ve la class de delegación:

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

Y la class de statement podría verse así:

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

Para encontrar properties que deleguen en una class de delegado junto con la instancia de esa class, aquí hay una function de utilidad:

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

Algunas notas:

  • Primero corrija su tipo reificado T a T: Any o no puede acceder a todas las extensiones en Kotlin reflection incluyendo declanetworkingMemberProperties
  • Es más fácil llegar al campo desde una reference de propiedad para asegurarse de que realmente está hablando de algo que realmente es una propiedad, por lo que para cada una de las properties de declanetworkingMemberProperties use javaField para hacerlo.
  • Como javaField es un getter personalizado y podría ser anulable, se guarda en una variable local para que el casting inteligente funcione más tarde.
  • Entonces, si este campo tiene el mismo tipo que la class de delegación que está buscando, puede acceder al campo.
  • Pero primero debes forzar la accesibilidad del campo porque es un campo private .

Ejecutando esto en el progtwig de testing:

 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}]") } } 

La salida es algo así como:

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

En el nivel de código de bytes, las properties delegadas no difieren de las normales (public getter / setter y private field).

Una forma de ir es escanear los campos privados de Example y filtrar aquellos que tienen el operator getValue(thisRef: R, KProperty<*>) . Técnicamente, un campo puede contener un object delegado val x = lazy {1} , pero eso no es muy probable.