android - 具有绑定(bind)类型参数的泛型父类(super class)型的 Kotlin 类型别名不适用于继承

标签 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

Error: Type argument is not within its bounds: should be subtype of 'SomeInterface'

错误表明它不是正确的子类型,但它是!

这种类型别名的用例来自现实生活中的代码,其中父类(super class)有 5 个类型参数,每个参数都有相当长的名称,而且我不想用不必要的垃圾邮件污染类 header 。有任何想法吗?我使用的是 kotlin 1.2.51。

--- 原始问题 ---

MVP 接口(interface):

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 的基础 fragment :

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 契约(Contract):

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

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

最终 fragment :

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 必须直接注入(inject)到目标类中(在本例中不仅仅是 Fragment > 或 MVPFragment,但 ExampleFragment),否则不会生成注入(inject)代码。

MVPFragment 中的注入(inject)如下所示:

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

最佳答案

问题是由以下原因引入的循环依赖:

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

关于android - 具有绑定(bind)类型参数的泛型父类(super class)型的 Kotlin 类型别名不适用于继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51573584/

相关文章:

android - 通过ForegroundService获取位置时应用崩溃

android - 如何将模型/POJO 与 android 数据绑定(bind)、房间和改造一起使用?

android - 可以将一个 ViewModel 用于多个 Activity 吗?

android - 使用 java 代码包含其他布局

scala - 为什么我不能声明用 null 初始化的参数化类型的变量?

函数指针的转换

android - 如何将对象的字段编码为字符串化 JSON 而不是 Moshi 中的嵌套 JSON 对象?

android - 错误: Failed to find 'ANDROID_HOME' environment variable when building apk using ionic

generics - 如何实现采用特征MyTrait <A>的结构? [复制]

android - 如何修复 Koin lib 中的 "No compatible definition found for type ' 上下文?