Получить свойство KProperty свойства расширения без пакета

В kotlin вы можете использовать ссылочный оператор для получения KProperty свойства расширения пакета следующим образом:

val String.extProp: String get() = "Some get code" fun foo() { val prop: KProperty<String> = String::extProp } 

Однако, когда свойство расширения объявляется внутри класса, оператор ссылки больше не работает:

 class Example() { val String.extProp: String get() = "Some get code" fun foo() { val prop: KProperty<String> = String::extProp // error } } 

Так что мне интересно, как я могу изменить проблемную строку во втором примере, чтобы получить KProperty?

Ошибка, которую вы получаете:

Ошибка: (y, x) Kotlin: «extProp» является членом и расширением одновременно. Ссылки на такие элементы не допускаются

Механизм синтаксиса не существует для создания ссылки на метод расширения, который также требует наличия класса. Например, ваше расширение может использовать членов класса, и для этого потребуется что-то вроде « связанных ссылок », поступающих в Kotlin 1.1 (что я не уверен, что это также рассмотрит этот вопрос, в настоящее время это открытый вопрос ). Так что пока нет синтаксиса :: . Такие вещи, как Example::String::extProp , недоступны, ни один из них не используется, как обычно, Example::String.extProp . Но вы можете найти это путем размышления.

Сначала вам нужно знать, какой тип вы получите:

 KProperty2<INSTANCE, EXTENDING, PROPTYPE> 

Если нормальное свойство класса:

 KProperty1<INSTANCE, PROPTYPE> 

Вы должны знать, что, поскольку для любого вызова getter потребуется экземпляр класса и экземпляр класса, свойство которого расширяется. Таким образом, вы не можете называть его так же, как и ссылку на свойство класса.

Вы можете использовать эту функцию для поиска свойства расширения, объявленного в классе:

 @Suppress("UNCHECKED_CAST") fun <T: Any, EXTENDING: Any, R: Any> KClass<T>.extProp(extends: KClass<EXTENDING>, name: String, returning: KClass<R>): KProperty2<T, EXTENDING, R> { return this.declaredMemberExtensionProperties.first { it.name == name && it.parameters.size == 2 && it.parameters[0].kind == KParameter.Kind.INSTANCE && it.parameters[0].type == this.defaultType && it.parameters[1].kind == KParameter.Kind.EXTENSION_RECEIVER && it.parameters[1].type == extends.defaultType && it.returnType == returning.defaultType } as KProperty2<T, EXTENDING, R> } 

Это немного избыточно для проверки, но гарантирует, что оно будет надежным в будущем, если позже будут добавлены другие типы расширений. Ниже приведен код, обновленный для его использования:

 class Example() { val String.extProp: String get() = "howdy $this" fun foo() { val prop = Example::class.extProp(String::class, "extProp", String::class) println(prop.get(this, "stringy")) // "howdy stringy" } }