DTechnlogy
DTechnlogy

Reputation: 345

Function that accept all class that inherited from generic in kotlin

I'm trying to add Example class into a list of Delegate through addDelegate function. Unfortunately, I got an error :

TypeMismatch: Required Delegate<Item, CoreHolder> found Example

Here's my code (It's not full code, it just some piece of code that relevant to my question):

interface Delegate <T, VH: CoreHolder> {
    fun onCreate(parent: ViewGroup): VH

    fun onBind(items: List<T>, holder: VH)
}

class DelegateManager<T, VH: CoreHolder> {
    private val delegates = mutableListOf<Delegate<T, VH>>()

    fun addDelegate(delegate: Delegate<T, VH>) {
        delegates.add(delegate)
    }
}

class GenericDelegateManager<T> {
    private val delegateManager = DelegateManager<T, CoreHolder> = DelegateManager()

    fun addDelegate(delegate: Delegate<T, CoreHolder>) {
        delegateManager.addDelegate(adapterDelegate)
    }
}

class Main {
    val genericDelegateManager = GenericDelegateManager<Item>()
    fun main() {
        genericDelegateManager.addDelegate(Example())
        genericDelegateManager.addDelegate(Example2())
    }
}

class Example: Delegate<Item, Example.ViewHolder> {
    class ViewHolder: CoreHolder {
        //...
    }
}
class Example2: Delegate<Item, Example2.ViewHolder> {
    class ViewHolder: CoreHolder {
        //...
    }
}

Current workarounds : I've found 2 workarounds but I think it's not the best way for doing it,

  1. Change the addDelegate function's parameter to Delegate<T, out CoreHolder> and cast it to Delegate<T, CoreHolder> but I got a warning "Unchecked Cast". So the code become
    @SurpressWarning("UNCHECKED_CAST")
    fun addDelegate(delegate: Delegate<T, out CoreHolder>) {
        delegates.add(delegate as Delegate<T, CoreHolder>)     
    }
  1. Change the Delegate interface type parameter to <T, out VH> and change onBind to fun onBind(items: List<T>, holder: @UnsafeVariance VH) so the code become
    interface Delegate <T, out VH: CoreHolder> {
        fun onBind(items: List<T>, holder: @UnsafeVariance VH)
    }

All those two solutions work, can run and behave as expected. But the code isn’t that fancy.

Is there another better way to solve this kind of problem? Thanks

Upvotes: 1

Views: 155

Answers (1)

Manushin Igor
Manushin Igor

Reputation: 3689

Short - it is impossible to combine these classes to the one DelegateManager. The task can be simplified to the following:

fun <TKey> someMethod(pair1: Pair1<TKey>, pair2: Pair2<TKey>) {
    val map = mutableMapOf<TKey, ???>()

    map[pair1.key] = pair1.value
    map[pair2.key] = pair2.value
}

class Pair1<TKey>(val key: TKey, val value: String)
class Pair2<TKey>(val key: TKey, val value: Int)

As you can see, you couldn't replace ??? to anything, which provides compilable code.

However example can be reworked to:

fun <TKey> someMethod(pair1: Pair<TKey, CiImpl1>, pair2: Pair<TKey, CiImpl2>) {
    val map = mutableMapOf<TKey, CommonInterface>()

    map[pair1.key] = pair1.value
    map[pair2.key] = pair2.value
}

class Pair<TKey, TValue: CommonInterface>(val key: TKey, val value: TValue)

class CiImpl1: CommonInterface
class CiImpl2: CommonInterface

interface CommonInterface

Finally: you couldn't put Example and Example2 classes into the common collection, the same with my code. Moreover, you couldn't just use Delegate<?, CoreHolder>, because it accepts any implementation of CoreHolder, which is not acceptable for you.

Upvotes: 1

Related Questions