Reputation: 824
I'm lost in generic types many hours. I want to simplified the code but I can't cast object when its generic type. How I can solve this problem or another simplified way? (I'm use kotlin 1.2)
sealed class SETTING(override val key: String) : SettingsKeyContract
object optFirstLaunch : SETTING("first_launch"), SettingsKeyContractWithType<Boolean> {
override val defaults = true
}
object optNotifications : SETTING("notification_list"), SettingsKeyContractWithType<List<String>> {
override val defaults = emptyList<String>()
}
interface SettingsKeyContract { val key: String }
interface SettingsKeyContractWithType<T : Any> : SettingsKeyContract {
val defaults: T
@Suppress("UNCHECKED_CAST")
fun get(): T? = (App.getContentComponent()?.getSettings()?.get(key)?.value?.data as? T)
fun remove() = (App.getContentComponent()?.getSettings())?.delete(key)
fun save(value: T) = (App.getContentComponent()?.getSettings()?.add(key, value))
}
class OptionModel(@OPTIONS_ID optionId: Int, contract: SettingsKeyContract)
val optionModel = OptionModel(1, optNotifications)
when(optionModel.contract){
is SettingsKeyContractWithType<List<String>> -> (optionModel.contract as SettingsKeyContractWithType<List<String>>).set(listOf("ring-1", "ring-2")) //error
is SettingsKeyContractWithType<Boolean> -> (optionModel.contract as SettingsKeyContractWithType<Boolean>).set(true) //error
}
Error:
Cannot check for instance of erased type: SettingsKeyContractWithType<...>
Upvotes: 0
Views: 4166
Reputation: 148149
Please take a look at the explanation of type erasure and type checks for generic types in the language reference: Type erasure and generic type checks.
Basically, you cannot do that sort of check because the instances of SettingsKeyContractWithType
do not hold any information about their actual type argument at runtime.
An option that you could try here is to add make SettingsKeyContractWithType
explicitly store some representation of the type argument. A simple KClass
does not seem to fit, because it cannot represent a concrete generic type (you cannot have a KClass
for List<String>
.
If that's really what you want, consider using the technique of super type tokens, as described here: (link).
You can add a TypeReference<T>
property to SettingsKeyContractWithType
, fill it within an inline factory function with a reified type parameter.
Upvotes: 2