Как получить общий класс параметров в Котлине

Firebase's snapshot.getValue() ожидает, что будет вызван следующим образом:

 snapshot?.getValue(Person::class.java) 

Однако я хотел бы заменить Person на общий параметр, который передается в класс через объявление класса, т.е.

 DataQuery<T : IModel> 

и используйте этот общий параметр, чтобы сделать что-то вроде этого:

 snapshot?.getValue(T::class.java) 

но когда я пытаюсь, я получаю сообщение об ошибке

только классы могут быть использованы в левой части литерала класса

Можно ли предоставить ограничение класса на общий параметр, как в C #, или есть ли какой-то другой синтаксис, который я могу использовать для получения информации о типе для общего параметра?

Что вам нужно, это модификатор reify для вашего общего параметра, вы можете прочитать об этом здесь. https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters Итак, если вы сделаете что-то вроде этого:

 inline fun <reified T : Any>T.logTag() = T::class.java.simpleName 

вы получите имя фактического класса вызывающего, а не «Объект».

Для класса с общим параметром T вы не можете этого сделать, потому что у вас нет информации о типе для T, поскольку JVM стирает информацию о типе. Поэтому такой код не может работать:

 class Storage<T: Any> { val snapshot: Snapshot? = ... fun retrieveSomething(): T? { return snapshot?.getValue(T::class.java) // ERROR "only classes can be used..." } } 

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

 class Storage { val snapshot: Snapshot? = ... inline fun <reified T: Any> retrieveSomething(): T? { return snapshot?.getValue(T::class.java) } } 

Обратите внимание, что встроенная функция, если public может обращаться только к открытым членам класса. Но вы можете иметь два варианта функции: тот, который получает параметр класса, который не является встроенным, и получает доступ к частным внутренним элементам, а также другую встроенную вспомогательную функцию, которая выполняет переопределение из параметра inferred type:

 class Storage { private val snapshot: Snapshot? = ... fun <T: Any> retrieveSomething(ofClass: Class<T>): T? { return snapshot?.getValue(ofClass) } inline fun <reified T: Any> retrieveSomething(): T? { return retrieveSomething(T::class.java) } } 

Вы также можете использовать KClass вместо Class чтобы вызывающие абоненты, которые являются только Kotlin, могут просто использовать MyClass::class вместо MyClass::class.java

Если вы хотите, чтобы класс взаимодействовал с встроенным методом для генериков (это означает, что класс Storage хранит только объекты типа T ):

 class Storage <T: Any> { val snapshot: Snapshot? = ... inline fun <reified R: T> retrieveSomething(): R? { return snapshot?.getValue(R::class.java) } } 

Ссылка на типы reified в встроенных функциях: https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters