Kotlin 泛型:Kotlin 无法通过正确的继承识别我的 class

Kotlin Generics: Kotlin does not recognize my class with correct inheritance

这是我的简化示例:

interface IMyView

interface IMyViewModel<VIEW : IMyView, in ITEM> {

    fun attachView(view: VIEW)

    fun getView(): VIEW?
}


class myView : IMyView

class MyViewModel : IMyViewModel<myView, String> {
    override fun attachView(view: myView) {
        TODO("not implemented")
    }

    override fun getView(): myView? {
        TODO("not implemented")
    }
}


abstract class MyBaseClass<VIEWMODEL : IMyViewModel<out IMyView, *>> : IMyView {

    protected lateinit var viewModel: VIEWMODEL

    fun myInvocation(): Unit {
        viewModel.attachView(this as IMyView)
    }
}

class MyMainClass : MyBaseClass<MyViewModel>()

问题出在最后一行,因为 MyViewModel 未被识别为 IMyViewModel。报错信息如下:

Type argument is not within its bounds. 
Expected: IMyViewModel<IMyView, *>
Found: MyViewModel

在 Java 中有效。我必须进行哪些调整才能使其在 Kotlin 中也能正常工作?

****** 更新 ******

如果你使用

abstract class MyBaseClass<VIEWMODEL : IMyViewModel<out IMyView, *>>

(请参阅上面更新的 Kotlin 代码)

然后我无法调用 myInvocation,因为对于该调用我需要 'in IMyView'。 因此,这是一场灾难。我所做的一切都会导致其他问题。在 Java.

中更容易

你的代码的问题是,当你设定一个上限 VIEWMODEL : IMyViewModel<IMyView, *> 时,一个类型可以满足这个界限 只有 如果它实现 IMyViewModel VIEW 类型参数将 完全 替换为 IMyView,不允许 IMyView 的子类型(因此 MyViewModel 被拒绝)。换句话说,VIEW is invariant.

由于 Kotlin 允许您在声明点和使用点都指定类型参数差异,您可以通过执行以下操作之一来解决此问题:

  • 使 IMyViewModelVIEW 类型参数与声明位置方差协变:

    interface IMyViewModel<out VIEW : IMyView, in ITEM>  
                           ^^^
    
  • VIEWMODEL上界的IMyViewModel的使用位置添加一个out投影:

    abstract class MyBaseClass<VIEWMODEL : IMyViewModel<out IMyView, *>>
                                                        ^^^
    
  • 将另一个类型参数T添加到MyBaseClass并在IMyViewModel<T, *>中使用它:

    abstract class MyBaseClass<T : IMyView, VIEWMODEL : IMyViewModel<T, *>>
    class MyMainClass: MyBaseClass<myView, MyViewModel>()
    

我现在解决了这个问题。我犯了一个概念错误。这是解决方案:

interface IMyViewModel<VIEW : IMyView, in ITEM> {

    fun attachView(view: VIEW)

    fun getView(): VIEW?
}


class MyViewModel : IMyViewModel<IMyView, String> {
    override fun attachView(view: IMyView) {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun getView(): IMyView? {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
}


abstract class MyBaseClass<VIEWMODEL : IMyViewModel<IMyView, *>> : IMyView {

    protected lateinit var viewModel: VIEWMODEL

    fun myInvocation(): Unit {
        viewModel.attachView(this)
    }
}

class MyMainClass : MyBaseClass<MyViewModel>()