2017-08-01 150 views
2

这是我简单的例子:科特林泛型:科特林不承认我的类继承正确

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, *>> 

(请参见上面的更新科特林代码)

那么我不能叫myInvocation因为那个电话我需要'IMyView'。 因此这是一场灾难。我所做的一切都会导致其他问题。在Java中更容易。

回答

0

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

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>() 
1

与您的代码的问题是,当你做出一个上限VIEWMODEL : IMyViewModel<IMyView, *>,一种能满足这种约束只有是否实现IMyViewModelVIEW类型参数与IMyView取代正是,没有IMyView亚型允许(因此MyViewModel被拒绝)。换句话说,VIEW is invariant

由于科特林让您无论是在声明的网站和使用网站指定类型参数的变化,则可以通过执行下列操作之一解决这个问题:

  • IMyViewModel协的VIEW类型参数与报关现场方差:

    interface IMyViewModel<out VIEW : IMyView, in ITEM> 
             ^^^ 
    
  • IMyViewModel使用现场的VIEWMODEL上限添加out -projection:

    abstract class MyBaseClass<VIEWMODEL : IMyViewModel<out IMyView, *>> 
                    ^^^ 
    
  • IMyViewModel<T, *>添加其他类型的参数TMyBaseClass并使用它:

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

你是对的,那是有效的。但我有IMyViewModel有两个乐趣的附加问题:有趣的attachView(view:VIEW),有趣的getView():VIEW?有趣的attachView(视图:视图)将无法使用,因为它是在那里。我能做什么? – grenzfrequence

+0

@grenzfrequence,那么你只能应用use-site方差,并且你将无法安全地调用'attachView(view:VIEW)',因为'VIEW'没有下界(它可以是任何的子类型'IMyView')。如果这不符合您的用例,您可以尝试将另一个类型参数添加到'MyBaseClass',请参阅已更新的答案。 – hotkey

+0

@grenzfrequence,我检查了更新的问题,并且似乎更新后的答案的最后一点解决了问题。 – hotkey