具有绑定类型参数的泛型超类型的Kotlin类型别名不适用于继承

时间:2018-07-28 17:14:42

标签: android generics kotlin mvp type-alias

TL; DR为何起作用:

interface SomeInterface
interface Generic <T : SomeInterface> {}
class Self : Generic<Self>, SomeInterface

这不是:

interface SomeInterface
interface Generic <T : SomeInterface> {}
typealias Specified = Generic<Self>
class Self : Specified, SomeInterface
  

错误:类型参数不在其范围内:应该是的子类型   'SomeInterface'

错误说这不是正确的子类型,但是是!

这种类型别名的用例来自现实生活中的代码,其中超类具有5个类型参数,每个参数的名称都比较长,我不想用不必要的垃圾邮件来污染类头。有任何想法吗?我正在使用Kotlin 1.2.51。

---原始问题---

MVP接口:

interface MVPComponent // dagger component 
interface MVPComponentHolder<C : MVPComponent> // implementing class must provide component
interface MVPArgs // args passed from view to presenter on attach
interface MVPView<A : MVPArgs> // MVP View, must provide Args for presenter
interface MVPPresenter<T : MVPView<A>, A : MVPArgs, U : MVPUseCase>
interface MVPUseCase // selected API methods to use in presenter

MVP的基础片段:

abstract class MVPFragment<F, V, P, A, C>
    : Fragment(), MVPComponentHolder<C>
    where F : V,
          V : MVPView<A>,
          P : MVPPresenter<V, A, *>,
          C : MVPComponent<V>,
          A : MVPArgs {
    // lots of MVP logic
}

MVP合同:

interface ExampleMVP {
    data class Args(/* ... */) : MVPArgs

    interface View : MVPView<Args> {
        //...
    }
    interface Presenter : MVPPresenter<View, Args, UseCase> {
        //...
    }
    interface UseCase : MVPUseCase<View> {
        //...
    }
}

最终片段:

class ExampleFragment : MVPFragment<
    ExampleFragment,
    ExampleMVP.View,
    ExampleMVP.Presenter,
    ExampleMVP.Args,
    ExampleMVP>(), ExampleMVP.View {
    // final fragment logic
}

但是我想使用以下语法:

private typealias SuperFragment = MVPFragment<
        ExampleFragment,
        ExampleMVP.View,
        ExampleMVP.Presenter,
        ExampleMVP.Args,
        ExampleMVP>

class ExampleFragment : SuperFragment(), ExampleMVP.View {
    // final fragment logic
}

我将ExampleFragment作为MVPFragment的类型参数的原因是,Dagger 2必须直接注入目标类(在这种情况下,不仅是FragmentMVPFragment,而且是ExampleFragment),否则将不会生成注入代码。

MVPFragment中的注入看起来如下:

@CallSuper
override fun onAttach(context: Context) {
    super.onAttach(context)
    component.injectIntoView(this as F) // must be target fragment type (here F)
}

1 个答案:

答案 0 :(得分:1)

问题是由以下人员引入的循环依赖关系:

class Self : Specified, SomeInterface

如果Self不继承自Specified,则它起作用。

更改后的示例如下。

interface SomeInterface
interface Generic <T : SomeInterface> {}
typealias Specified = Generic<Self>
class Self : SomeInterface

关于您的原始问题。我认为您无法完全实现这一点,但是可以像这样减少所需的类型参数的数量:

class ExampleFragment : SuperFragment<ExampleFragment>(), ExampleMVP.View {
    // final fragment logic
}

private typealias SuperFragment<T> = MVPFragment<
        T,
        ExampleMVP.View,
        ExampleMVP.Presenter,
        ExampleMVP.Args,
        ExampleMVP<ExampleMVP.View, ExampleMVP.Args>>