Kotlin数据类:如果在编译时我不知道它的名字,如何读取属性的值?

Eli*_*ley 12 kotlin data-class

如果属性名称仅在运行时已知,我如何读取Kotlin数据类实例中的属性值?

Jay*_*ard 20

这是一个从给定属性名称的类实例中读取属性的函数(如果找不到属性则抛出异常,但您可以更改该行为):

import kotlin.reflect.KProperty1
import kotlin.reflect.full.memberProperties

@Suppress("UNCHECKED_CAST")
fun <R> readInstanceProperty(instance: Any, propertyName: String): R {
    val property = instance::class.memberProperties
                     // don't cast here to <Any, R>, it would succeed silently 
                     .first { it.name == propertyName } as KProperty1<Any, *> 
    // force a invalid cast exception if incorrect type here
    return property.get(instance) as R  
}
Run Code Online (Sandbox Code Playgroud)

示例用法:

// some data class
data class MyData(val name: String, val age: Int)
val sample = MyData("Fred", 33)

// and reading property "name" from an instance...
val name: String = readInstanceProperty(sample, "name")

// and reading property "age" placing the type on the function call...
val age = readInstanceProperty<Int>(sample, "age")

println(name) // Fred
println(age)  // 33
Run Code Online (Sandbox Code Playgroud)

注意:需要kotlin-reflect依赖

  • @HatemJaber:较新版本的反射库允许使用`instance :: class.members`而不是`instance.javaClass.kotlin.declaredMemberProperties,尽管您应检查属性的类型为`KProperty &lt;*,*&gt;`。或`KMutableProperty &lt;*,*&gt;`。 (3认同)
  • 我知道这个答案将近2年了...这仍然是这样做的方法吗?我很好奇,是否有任何新的东西可能会添加到Kotlin API中,从而创造出另一种方法来实现这一目标。 (2认同)

hot*_*key 16

你可以通过反射来完成它,对于数据类和普通类都是如此.

第一个选项就是使用Java反射:

val name = obj.javaClass
              .getMethod("getName") // to get property called `name`
              .invoke(obj)
Run Code Online (Sandbox Code Playgroud)

你甚至可以做一个扩展功能:

inline fun <reified T : Any> Any.getThroughReflection(propertyName: String): T? {
    val getterName = "get" + propertyName.capitalize()
    return try {
        javaClass.getMethod(getterName).invoke(this) as? T
    } catch (e: NoSuchMethodException) {
        null
    }
}
Run Code Online (Sandbox Code Playgroud)

它叫公共吸气剂.要获取私有属性的值,您可以使用getDeclaredMethod和修改此代码setAccessible.这也将与相应的获取Java对象的工作(但它错过了约定ishas干将为boolean).

用法:

data class Person(val name: String, val employed: Boolean)

val p = Person("Jane", true)
val name = p.getThroughReflection<String>("name")
val employed = p.getThroughReflection<Boolean>("employed")

println("$name - $employed") // Jane - true
Run Code Online (Sandbox Code Playgroud)


第二个选项涉及使用kotlin-reflect库,您应该单独添加到项目中,这是它的文档.它将让您获得实际的Kotlin属性值,忽略Java getter.

您可以使用javaClass.kotlin获取实际的Kotlin类令牌,然后从中获取属性:

val name = p.javaClass.kotlin.memberProperties.first { it.name == "name" }.get(p)
Run Code Online (Sandbox Code Playgroud)

此解决方案仅适用于Kotlin类,而不适用于Java类,但如果您需要使用Kotlin类,则它更可靠:它不依赖于底层实现.

  • 这是我的观点的一部分:不是假设和依赖低级方法,而是最好依靠Kotlin反射支持属性(即答案的第二部分)或处理Java Bean的高级Java抽象. (2认同)

Ada*_*Kis 8

上面的答案对我不起作用,所以我为此创建了一个扩展函数:

@Throws(IllegalAccessException::class, ClassCastException::class)
inline fun <reified T> Any.getField(fieldName: String): T? {
    this::class.memberProperties.forEach { kCallable ->
        if (fieldName == kCallable.name) {
            return kCallable.getter.call(this) as T?
        }
    }
    return null
}
Run Code Online (Sandbox Code Playgroud)

这是一个示例调用:

val valueNeeded: String? = yourObject.getField<String>("exampleFieldName")
Run Code Online (Sandbox Code Playgroud)

还要将它包含在您的应用的 build.gradle 中:

implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
Run Code Online (Sandbox Code Playgroud)

  • 这个答案对我有用。谢谢 (2认同)

归档时间:

查看次数:

11557 次

最近记录:

6 年,3 月 前