在这个场景中,我有一个超级抽象类,它使用Kotlin sealed classes发出不同类型的事件。
这些事件的模型如下。
sealed class BaseEvent {
object ConnectionStarted : BaseEvent()
object ConnectionStopped : BaseEvent()
}
sealed class LegacyEvent : BaseEvent() {
object TextChanged : LegacyEvent()
object TextCleared : LegacyEvent()
}
sealed class AdvancedEvent : BaseEvent() {
object ButtonClick : AdvancedEvent()
object ButtonLongClick : AdvancedEvent()
}下面是发出这些事件的类
abstract class BaseViewModel<E : BaseEvent> {
private fun startConnection() {
emit(BaseEvent.ConnectionStarted) // <-- Error
}
fun emit(event: E){
//...
}
}
class LegacyBaskan : BaseViewModel<LegacyEvent>() {
fun textChanged() {
emit(LegacyEvent.TextChanged) // <-- Works
}
}
class AdvancedBaskan : BaseViewModel<AdvancedEvent>() {
fun buttonClicked() {
emit(AdvancedEvent.ButtonClick) // <-- Works
}
}在这里,它只对子类起作用,我可以在它们关联的类中发出LegacyEvent或AdvancedEvent中的任何事件。但是,对于BaseBaskan类,我不能从BaseEvent发出事件,尽管我声明泛型E必须扩展BaseEvent。
我需要每个子类访问自己的事件和超类事件,而不是其他子类的事件。
如何仍然可以在基类中从BaseEvent 发出事件,同时赋予每个类仅发出自己事件的权限?
发布于 2021-10-21 12:49:02
不确定您是否对为什么不允许从基类发出项感到困惑。由于E可以是BaseEvent的任何子类型,如果您的类可以发出ConnectionStarted,那么它在声明为BaseViewModel<AnythingBesidesConnectionStarted>时就会违反它的约定。
我能想到的唯一办法就是拥有emit函数的私有和公共版本。您可能必须在类的其他地方更改尚未显示的代码。如果有返回E的函数,则必须对其进行更改,使其返回BaseEvent。
abstract class BaseViewModel<E : BaseEvent> {
private fun startConnection() {
emitInternal(BaseEvent.ConnectionStarted)
}
private fun emitInternal(event: BaseEvent) {
//...
}
fun emit(event: E){
emitInternal(event)
}
}发布于 2021-10-21 12:51:48
您不能在BaseEvent.ConnectionStarted中发出BaseViewModel (以及其他事件),因为E还没有定义,所以类型系统不能确定您不会发出另一个破坏泛型类型不变性的子类型的事件。
只需添加一个重载的私有版本,该版本接受BaseEvent参数(您将需要一些@JvmName注释使其可用于JVM目标):
abstract class BaseViewModel<E : BaseEvent> {
private fun startConnection() {
emit(BaseEvent.ConnectionStarted)
}
@JvmName("emitBaseEvent")
private fun emit(event: BaseEvent) {
//...
}
fun emit(event: E) {
emit(event as BaseEvent)
}
}发布于 2021-10-21 13:15:49
看起来您需要反方差,这可以使用in实现。假设基类只具有诸如emit之类的方法,这些方法使用E类型作为参数类型,而不是作为返回类型,那么:
abstract class BaseViewModel<in E : BaseEvent> {见https://kotlinlang.org/docs/generics.html#use-site-variance-type-projections。
https://stackoverflow.com/questions/69658281
复制相似问题