2015-12-06 4 views
8

Firebase-х snapshot.getValue() ожидает называться следующим образом:Как получить универсальный класс параметра в Котлин

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

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

DataQuery<T : IModel> 

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

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

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

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

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

+0

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

+0

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

ответ

12

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

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

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

+6

Не забудьте объявить свой параметр типа как «T: Any», иначе он будет иметь значение NULL. –

+2

Кроме того, не забывайте, что функция должна быть объявлена ​​встроенной. – mhlz

11

Для класса с общим параметром 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..." 
    } 
} 

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

class Storage { 
    val snapshot: Snapshot? = ... 

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

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

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, так что абоненты, которые Котлин только могут просто использовать 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) 
    } 
} 

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

+1

У меня есть класс 'абстрактный класс ViewModelFragment : Fragment()' и метод внутри 'ViewModelProviders .of (somethingNotInteresting) .get (getViewModelClass())' дает T.class: java из вашего кода 'inline fun getViewModelClass(): класс = R :: class.java', но компилятор жалуется, что «не может использовать« T »как повторно определенный тип. Вместо этого используйте« Класс ». Вы знаете, как это исправить? – murt