Kotlin:按照定义的顺序通过反射获取数据类的成员

luk*_*s.j 6 reflection kotlin

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

data class SomeDataClass(
  var id: String,
  var name: String,
  var deleted: String
)
Run Code Online (Sandbox Code Playgroud)

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

import kotlin.reflect.full.memberProperties

val properties = SomeDataClass::class.memberProperties

print(properties.map { it.name })   // prints:   [deleted, id, name]
Run Code Online (Sandbox Code Playgroud)

print 语句中的映射将返回一个列表,其中包含按字母顺序排列的属性名称。我需要按照源代码中定义的顺序列出列表,在本例中为:[id、name、deleted]。

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

val SomeDataClass_Order = listOf("id", "name", "deleted")
Run Code Online (Sandbox Code Playgroud)

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

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

Swe*_*per 5

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

val propertyNames = SomeDataClass::class.primaryConstructor!!.parameters.map { it.name }
Run Code Online (Sandbox Code Playgroud)

如果你想要KPropertys:

val properties = propertyNames.map { name -> 
    SomeDataClass::class.memberProperties.find { it.name == name } 
}
Run Code Online (Sandbox Code Playgroud)

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

我不知道其他平台,但是在 Kotlin/JVM 上,没有指定类文件中生成属性的支持字段的顺序,快速实验发现该顺序(至少对于我现在正在使用的 kotlinc),顺序与声明顺序相同。所以理论上,你可以读取数据类的类文件,并找到字段。请参阅此相关答案以按顺序获取方法。或者,您可以使用 Java 反射,它也不保证返回字段的任何顺序,但“恰巧”按声明顺序返回它们:

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

如果您确实也想按顺序获取类体内声明的属性,我建议您根本不依赖顺序。

  • 你用 ...::class.java.declaredFields.toList() 救了我。 (2认同)