Как получить класс параметра универсального типа в Kotlin - PullRequest
0 голосов
/ 21 сентября 2018

Я хотел бы получить свойство класса из универсального типа T.Я решил расширить до Any, но получаю ошибку.https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html#extension-properties

У меня есть следующий код:

class FirebaseDBRepo<T : Any>(val child:String) {

private var callback: FirebaseDatabaseRepositoryCallback<T>? = null
private val ref: DatabaseReference
private val listener = object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {

        //T::class.java is showing the error cannot use t as reified type parameter use class instead

        val gameDS = dataSnapshot.getValue(T::class.java)
        callback!!.onSuccess(gameDS!!)
    }

    override fun onCancelled(databaseError: DatabaseError) {

    }
}

init {
    ref = FirebaseDatabase.getInstance().reference.child(child)
}


fun addListener(callback: FirebaseDatabaseRepositoryCallback<T>) {
    this.callback = callback
    ref.addValueEventListener(listener)
}

fun removeListener() {
    ref.removeEventListener(listener)
}

}

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Вы можете получить класс только по переменным.То же самое происходит в Java, но с немного другим сообщением:

public <T> void x(){
    T t = T.class.newInstance();
}

В Java вы можете решить это следующим образом:

public <T> void x(Class<T> cls){
    T t = cls.newInstance();
}

То же самое относится к Kotlin, и любойзвонки.Вам нужно будет получить экземпляр класса в большинстве случаев.Тем не менее, Kotlin поддерживает обобщенные обобщенные типы, используя ключевое слово, но только для встроенных обобщенных функций.Вы можете передать класс, но в функциях это действительно просто, просто используя ключевое слово reified.

Так как вы не можете объявить класс с обобщенными обобщенными типами, то есть это недопустимо:

class SomeClass<reified T>

Но это действительно для встроенных функций, то есть вы можете сделать:

inline fun <reified T> someFunction()

Таким образом, у вас есть два варианта.Но так как вы расширяете слушателя, первый вариант добавления обобщений в функцию не вариант.Вы не можете переопределить неуниверсальный метод с помощью дженериков.Это не скомпилируется.

Что оставляет второй вариант, который, к сожалению, довольно хакерский;передача класса конструктору.Итак, это должно выглядеть так:

class FirebaseDBRepo<T : Any>(val child: String, private val cls: Class<T>) {

Теперь я не использую Firebase, поэтому я понятия не имею, какие классы вы будете проходить, поэтому для следующего примера я просто использую String.

Kotlin поддерживает минимизацию некоторых типов, не переходя к необработанным типам.Это:

val t = FirebaseDBRepo<String>("", String::class.java)

Можно сократить до этого:

val t = FirebaseDBRepo("", String::class.java)

Предполагаемый тип в обоих случаях: FirebaseDBRepo<String>.

0 голосов
/ 21 сентября 2018

Поскольку вы работаете на JVM, стирание типов - это вещь.Это означает (в упрощенном виде), что во время компиляции генерики просто игнорируются.Следовательно, вы не можете получить класс T, поскольку JVM даже не знает, что вы подразумеваете под «T».

Котлин использует хитрый прием, чтобы обойти это ограничение в некоторых случаях.Когда вы используете встроенные функции, компилятор не вызывает определенную вами функцию, а вместо этого копирует все тело в место, где вы его вызвали.Это можно сделать только для встроенных функций.Не классы.

Есть обходной путь: просто добавьте private val classT: Class<T> в конструктор и используйте вместо этого параметр!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...