generics - 避免未经检查的演员表
问题描述
在以下情况下,我找不到避免未经检查的演员表的方法
class EventBus {
val eventToHandle: MutableMap<KClass<out Event>, Event.() -> Unit> = mutableMapOf()
final inline fun <reified T : Event> register(noinline handler: T.() -> Unit) {
@Suppress("UNCHECKED_CAST")
eventToHandle[T::class] = handler as Event.() -> Unit
}
fun fire(event: Event) {
eventToHandle[event::class]?.invoke(event)
?: throw IllegalStateException("Missing handler for class ${event::class}")
}
}
我的目标是强制映射仅包含具有Event
(或其子类型之一)作为接收器的 lambda,但同时我希望在注册 lambda 时引用实际实现。Event
通过这种方式,我可以使用他的实现成员,而无需每次都进行强制转换。
一个例子(requestId
是 的一个字段RequestExpiredEvent
):
eventBus.register<RequestExpiredEvent> {
requestService.setExpiredByRequestId(requestId)
}
我知道“消费者 lambda”没有协方差并且它们是逆变的,但我想是否有办法。我发现一个丑陋的解决方法是:
final inline fun <reified T : Event> register(crossinline block: T.() -> Unit) {
val handler: Event.() -> Unit = { this as T; block(this) }
eventToHandle[T::class] = handler
}
谢谢
解决方案
这是一个危险的演员阵容。SomeEventSubtype.() -> Unit
不是 的子类型Event.() -> Unit
。这是相反的方式。
假设 Event 是一个开放类并且你有这个子类:
class SubEvent: Event() {
fun hello(): Unit {
println("hello")
}
}
现在你尝试投射它:
val hello: SubEvent.() -> Unit = SubEvent::hello
val helloCasted = hello as Event.() -> Unit
当您尝试调用helloCasted.invoke(Event())
时,它会在尝试将您的事件转换为子事件时抛出 ClassCastException。您不能hello
使用任何实例Event
作为输入来调用,因为只有SubEvent
一个hello
函数可以调用。
如果您尝试隐式转换它,编译器将捕获此错误:
val hello: SubEvent.() -> Unit = SubEvent::hello
val helloCasted: Event.() -> Unit = hello // compiler error
它确实以相反的方式工作。在查看函数的输入时,您可以将类型层次结构视为倒置的。
val toStringFun: Event.() -> Unit = Event::toString
val toStringCasted: SubEvent.() -> Unit = toStringFun // OK
如果不在某处进行未经检查的强制转换,就没有办法解决这个问题,因为您在地图中存储了不同类型的对象。但是您需要将您的投射移动到该fire
函数,以便它知道将其投射到什么。您可以将函数作为类型存储Any
在地图中,因为无论如何您都会投射它们。像这样的东西:
class EventBus {
val eventToHandle: MutableMap<KClass<out Event>, Any> = mutableMapOf()
inline fun <reified T : Event> register(noinline handler: T.() -> Unit) {
eventToHandle[T::class] = handler
}
@Suppress("UNCHECKED_CAST")
inline fun <reified T : Event> fire(event: T) {
(eventToHandle[T::class] as? T.() -> Unit)?.invoke(event)
?: throw IllegalStateException("Missing handler for class ${event::class}")
}
}
推荐阅读
- java - 如何阅读许多多项式以及如何打印具有共同根和根的多项式?
- java - 不小心在文件夹中输入了 c_rehash cmd
- sql - 使用 CONCAT 的慢查询
- node.js - 无法读取未定义的反应属性“表情符号”-即使做出反应但无法收集
- spring-batch - 为 MultiResourceItemReader 编辑批处理
- r - r 编程 - 从维基百科抓取印度所有城镇的列表.. Wikipedi R 包
- elasticsearch - Grok 在调试器中成功并通过 input{stdin. 但无法输出到elasticsearch
- pytorch - NLLLoss 爆炸的原因
- android - 无法确定任务':app:installDebug'对Visual Studio代码的本机反应
- python - 有没有办法在 sklearn 上使用 MAPE(平均百分比误差)和 cross_validate?