【问题标题】:Kotlin: get members of a data class by reflection in the order they have been definedKotlin:按照定义的顺序通过反射获取数据类的成员
【发布时间】:2021-12-24 04:33:58
【问题描述】:

假设以下简单的示例数据类:

data class SomeDataClass(
  var id: String,
  var name: String,
  var deleted: String
)

使用以下代码可以获取属性(并设置或获取它们的值):

import kotlin.reflect.full.memberProperties

val properties = SomeDataClass::class.memberProperties

print(properties.map { it.name })   // prints:   [deleted, id, name]

print 语句中的映射将返回一个 List,其中包含按字母顺序排列的属性名称。我需要按照它们在源代码中定义的顺序列出,在这种情况下:[id, name, deleted]。

纯粹通过反思似乎无法实现。我能想出的唯一解决方案是使用定义顺序的辅助类:

val SomeDataClass_Order = listOf("id", "name", "deleted")

这对于一两个类来说不是问题,但对于数百个数据类来说却是个问题,其中最大的一个具有近百个属性。

欢迎任何想法。我不需要详细的代码,而是提示(如解析源代码、注释等)。

【问题讨论】:

    标签: kotlin reflection


    【解决方案1】:

    如果所有属性都在主构造函数中声明,你可以“作弊”:

    val propertyNames = SomeDataClass::class.primaryConstructor!!.parameters.map { it.name }
    

    如果你想要KPropertys:

    val properties = propertyNames.map { name -> 
        SomeDataClass::class.memberProperties.find { it.name == name } 
    }
    

    不幸的是,这没有找到在类主体中声明的属性。

    其他平台我不知道,但是在Kotlin/JVM上,类文件中属性的bac​​king fields的生成顺序是没有指定的,快速实验发现这个顺序(至少对于我现在正在使用的 kotlinc 版本),顺序与声明顺序相同。所以理论上,你可以读取数据类的类文件,找到字段。请参阅此related answer for getting the methods in order。或者,您可以使用 Java 反射,它也不保证返回字段的任何顺序,但“恰好如此”以声明顺序返回它们:

    // not guaranteed, might break in the future
    val fields = SomeDataClass::class.java.declaredFields.toList()
    

    如果你也想按顺序获取类体内声明的属性,我建议你完全不要依赖顺序。

    【讨论】:

    • 你用 ...::class.java.declaredFields.toList() 救了我。
    • @lukas.j 我应该再次警告您,订单无法保证,并且很可能会在其他 Kotlin 编译器版本和/或 JDK 版本中中断。
    • 我知道这一点。我只需要从遗留系统到新应用程序的一次性转移。我使用创建导出到 Excel 文件,因此一组员工可以快速检查数据并在旧系统中更正数据,然后再将其导入新系统。对于这些非 IT 员工来说,Excel 文件中的列顺序很重要。
    猜你喜欢
    • 1970-01-01
    • 2013-02-02
    • 2016-01-29
    • 1970-01-01
    • 1970-01-01
    • 2014-04-13
    • 2020-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多