I have a generic method like below
private fun <T> getSomething(): T {
return "something" as T
}
How can I call this method with a variable T
type?
val types = arrayListOf<Type>(String::class.java, Boolean::class.java)
types.forEach { type ->
val something = getSomething<type>() // Unresolved reference: type
}
At runtime, I don't know what would be generic type T
. I am getting the type from types
and should pass it with generic getSomething
method.
I want to call database which has several table. Example models are like this
class User{
}
class Student{
}
Since all the calling queries are basically same, I want to have generic method for calling database and get data.
private fun <T> getData(model: String): List<T>?{
return when(model){
"user" -> getUsers()
"student" -> getStudents()
else -> null
}
}
So when I call above method. Within my loop I want to pass Type
as either User
or Student
.
val types = arrayListOf<Type>(User::class.java, Student::class.java)
types.forEach { type ->
val data = getData<type>(type.javaClass.simpleName) // Unresolved reference: type in <type>
}
How can I achieve it.
Kotlin generic example When we call the generic method <T>printValue(list: ArrayList<T>) using printValue(stringList), the type T of method <T>printValue(list: ArrayList<T>)will be replaced by String type.
Type Erasure. As with Java, Kotlin's generics are erased at runtime. That is, an instance of a generic class doesn't preserve its type parameters at runtime. For example, if we create a Set<String> and put a few strings into it, at runtime we're only able to see it as a Set.
In order to use a generic type we must provide one type argument per type parameter that was declared for the generic type. The type argument list is a comma separated list that is delimited by angle brackets and follows the type name. The result is a so-called parameterized type.
"Out" keyword is extensively used in Kotlin generics. Its signature looks like this − List<out T> When a type parameter T of a class C is declared out, then C can safely be a super type of C<Derived>. That means, a Number type List can contain double, integer type list.
Here's a complete example:
import kotlin.reflect.KClass
data class User(val name: String)
data class Student(val name: String)
fun getUsers(): List<User> = listOf(User("JB"))
fun getStudents(): List<Student> = listOf(Student("Claire"))
fun <T: Any> getData(clazz: KClass<T>): List<T>? {
return when(clazz) {
User::class -> getUsers() as List<T>
Student::class -> getStudents() as List<T>
else -> null
}
}
fun main(args: Array<String>) {
val types = listOf(User::class, Student::class)
types.forEach { type ->
val data = getData(type)
println(data)
}
}
I would stick to concrete types like
import kotlin.reflect.KClass
interface IBaseData
interface IDataTable<out T> where T : IBaseData
{
fun getData(): List<T>
}
class User : IBaseData
class Student : IBaseData
class UserTable : IDataTable<User>
{
override fun getData(): List<User>
{
return listOf(User())
}
}
class StudentTable : IDataTable<Student>
{
override fun getData(): List<Student>
{
return listOf(Student())
}
}
inline fun <reified T: IBaseData> getDataTable() : IDataTable<T>?
{
return when(T::class)
{
User::class -> UserTable() as IDataTable<T>
Student::class -> StudentTable() as IDataTable<T>
else -> null
}
}
fun main()
{
var user = getDataTable<User>()?.getData()
var student = getDataTable<Student>()?.getData()
}
But still, it's an overhead, why not to use getUser()
or getStudents()
directly
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With