Это опасный состав. 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, когда попытается привести ваше Событие к SubEvent. Вы не можете вызвать 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}")
}
}