#kotlin #compilation #reflect
#kotlin #Сборник #отразить
Вопрос:
Я пишу систему сохранения для своей игры, используя делегированные свойства kotlin.
Вот небольшой пример
import kotlin.reflect.KProperty
object Test {
val test: Int by no_prop { 10 } // I want this
val testTwo: Int by prop(::testTwo) { 10 } // I don't want this if possible
}
inline fun <reified T : Any> Test.no_prop(initializer: () -> T) = TestProp<T>()
inline fun <reified T : Any> Test.prop(prop: KProperty<*>, initializer: () -> T): TestProp<T> {
println("My saving key is ${this.javaClass.simpleName}.${prop.name}")
return TestProp<T>()
}
class TestProp<T : Any> {
operator fun getValue(thisRef: Any?, property: KProperty<*>) = 10 as T
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {}
}
Моя игра использует строковый ключ для сохраненных свойств. Его всегда *callerClassName*.*propertyName*
Мне было интересно, возможно ли через мои функции расширения делегата или TestProp
класс для доступа к имени свойства делегирует?
Пример: Было бы неплохо, если бы метод no_prop мог, чтобы свойство, которое его вызывало, было названо «test»
val test: Int by no_prop { 10 }
Ниже приведен обходной путь, но я бы хотел избежать этого для каждого свойства, если это возможно
val testTwo: Int by prop(::testTwo) { 10 }
Ответ №1:
Вы можете. Всякий раз, когда вы создаете делегат, вы реализуете ReadOnlyProperty
(или ReadWriteProperty
):
public fun interface ReadOnlyProperty<in T, out V> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public operator fun getValue(thisRef: T, property: KProperty<*>): V
}
При попытке получить доступ к значению свойства для делегирования ( val test: Int by no_prop { 10 }
в вашем случае) getValue
будет вызвана функция, и у вас будет доступ к KProperty
. В нем есть name
поле, которое вы можете использовать для этой цели.
Это работает и для свойств класса, и для локальных свойств!
Комментарии:
1. Да, именно так я делаю это сейчас, но мне нужно было сделать это раньше, когда свойство создается. У меня возникла проблема, когда к такому свойству, как UID / GUID, не обращаются / часто не используются и не сохраняются, поскольку к нему никогда не обращались. Смотрите Мой ответ для решения.
2. Я понимаю. Это не то, что вы спрашивали.
Ответ №2:
Оказывается, у kotlin есть метод «provideDelategate», который вызывается при создании делегированного свойства. См. https://kotlinlang.org/docs/reference/delegated-properties.html#providing-a-delegate
Работает следующий код:
import kotlin.reflect.KProperty
object Test {
val test: Int by prop { 10 }
}
inline fun <reified T : Any> Test.prop(prop: KProperty<*>, initializer: () -> T) = TestProp<T>()
class TestProp<T : Any> {
operator fun getValue(thisRef: Any?, property: KProperty<*>) = 10 as T
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {}
// THIS IS CALLED ON INITIAL CREATION
operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): TestProp<T> {
println("My saving key is ${thisRef.javaClass.simpleName}.${property.name}")
return this
}
}
fun main() {
println(Test.test)
}