如何获得给定密封类的所有子类? [英] How to obtain all subclasses of a given sealed class?

查看:138
本文介绍了如何获得给定密封类的所有子类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我们将一个枚举类升级为以对象为子类的密封类 ,因此我们可以进行另一层抽象来简化代码.但是,我们无法再通过Enum.values()函数获取所有可能的子类,这很糟糕,因为我们严重依赖该功能.是否可以使用反射或任何其他工具来检索此类信息?

Recently we upgraded one of our enum class to sealed class with objects as sub-classes so we can make another tier of abstraction to simplify code. However we can no longer get all possible subclasses through Enum.values() function, which is bad because we heavily rely on that functionality. Is there a way to retrieve such information with reflection or any other tool?

PS:将它们手动添加到阵列是不可接受的.目前有45个,并且计划增加更多.

PS: Adding them to a array manually is unacceptable. There are currently 45 of them, and there are plans to add more.

这就是我们的密封类的样子:

This is how our sealed class looks like:

sealed class State

object StateA: State()
object StateB: State()
object StateC: State()
....// 42 more

如果有一个值集合,它将具有以下形状:

If there is an values collection, it will be in this shape:

val VALUES = setOf(StateA, StateB, StateC, StateC, StateD, StateE,
    StateF, StateG, StateH, StateI, StateJ, StateK, StateL, ......

自然没有人想要维护这样的怪物.

Naturally no one wants to maintain such a monster.

推荐答案

在Kotlin 1.3+中,您可以使用

In Kotlin 1.3+ you can use sealedSubclasses.

在以前的版本中,如果将子类嵌套在基类中,则可以使用

In prior versions, if you nest the subclasses in your base class then you can use nestedClasses:

Base::class.nestedClasses

如果将其他类嵌套在基类中,则需要添加过滤.例如:

If you nest other classes within your base class then you'll need to add filtering. e.g.:

Base::class.nestedClasses.filter { it.isFinal && it.isSubclassOf(Base::class) }

请注意,这为您提供了子类,而不是这些子类的实例(与Enum.values()不同).

Note that this gives you the subclasses and not the instances of those subclasses (unlike Enum.values()).

在您的特定示例中,如果State中的所有嵌套类都是您的object状态,则可以使用以下方法获取所有实例(例如Enum.values()):

With your particular example, if all of your nested classes in State are your object states then you can use the following to get all of the instances (like Enum.values()):

State::class.nestedClasses.map { it.objectInstance as State }


如果您真的想花哨的话,甚至可以扩展Enum<E: Enum<E>>,并使用


And if you want to get really fancy you can even extend Enum<E: Enum<E>> and create your own class hierarchy from it to your concrete objects using reflection. e.g.:

sealed class State(name: String, ordinal: Int) : Enum<State>(name, ordinal) {
    companion object {
        @JvmStatic private val map = State::class.nestedClasses
                .filter { klass -> klass.isSubclassOf(State::class) }
                .map { klass -> klass.objectInstance }
                .filterIsInstance<State>()
                .associateBy { value -> value.name }

        @JvmStatic fun valueOf(value: String) = requireNotNull(map[value]) {
            "No enum constant ${State::class.java.name}.$value"
        }

        @JvmStatic fun values() = map.values.toTypedArray()
    }

    abstract class VanillaState(name: String, ordinal: Int) : State(name, ordinal)
    abstract class ChocolateState(name: String, ordinal: Int) : State(name, ordinal)

    object StateA : VanillaState("StateA", 0)
    object StateB : VanillaState("StateB", 1)
    object StateC : ChocolateState("StateC", 2)
}

这使得您可以像调用其他任何Enum一样调用以下内容:

This makes it so that you can call the following just like with any other Enum:

State.valueOf("StateB")
State.values()
enumValueOf<State>("StateC")
enumValues<State>()


更新

直接扩展Enum在Kotlin中不再受支持.看 不允许显式扩展Enum类:KT-7773 .

Extending Enum directly is no longer supported in Kotlin. See Disallow to explicitly extend Enum class : KT-7773.

这篇关于如何获得给定密封类的所有子类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆