2017-08-01 89 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