具有绑定类型参数的通用超类型的 Kotlin typealias 不适用于继承
Kotlin typealias of generic supertype with bound type parameter not working for inheritance
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'
错误说它不是正确的子类型,但它是!
这种typealias的用例来自real-life代码,其中一个superclass有5个类型参数,每个都有相当长的名字,我不想污染class header 和不必要的垃圾邮件。有任何想法吗?我正在使用科特林 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 必须直接注入目标 class(在这种情况下不仅仅是 Fragment
或 MVPFragment
, 但 ExampleFragment
), 否则不会生成注入代码.
MVPFragment
中的注入如下所示:
@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>>
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'
错误说它不是正确的子类型,但它是!
这种typealias的用例来自real-life代码,其中一个superclass有5个类型参数,每个都有相当长的名字,我不想污染class header 和不必要的垃圾邮件。有任何想法吗?我正在使用科特林 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 必须直接注入目标 class(在这种情况下不仅仅是 Fragment
或 MVPFragment
, 但 ExampleFragment
), 否则不会生成注入代码.
MVPFragment
中的注入如下所示:
@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>>