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

    Несколько примечаний:

    • Сначала исправьте свой тип reified T to 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 field).

    Один из способов, которым вы могли бы пойти, – это сканировать частные поля Example и фильтровать те, у которых есть operator getValue(thisRef: R, KProperty<*>) . Технически поле может содержать объект-делегат val x = lazy {1} , но это маловероятно.