【问题标题】:How to set val property with Kotlin reflection?如何使用 Kotlin 反射设置 val 属性?
【发布时间】:2020-08-10 17:51:09
【问题描述】:

我想返回一个具有不同值的类的副本,该值分配给 val 属性。

data class Person(val name: String, val age: Int)

fun main() {
    val person = Person("Morné", 25)
    val property = person::class.declaredMemberProperties.first { it.name == "age" }
    person.copyWithValue(property.name, 22)
}

如果agevar,那么我可以这样做:

fun main() {
    val person = Person("Morné", 25)
    val property = person::class.declaredMemberProperties.first { it.name == "age" }
    if (property is KMutableProperty<*>)
        property.setter.call(person, 22)
}

【问题讨论】:

    标签: reflection kotlin kotlin-reflect


    【解决方案1】:

    如果你真的想只返回一个对象的副本,你可以使用copy,例如:

    fun main() {
      val person = Person("Morné", 25)
      val newPerson = person.copy(age = 22)
    }
    

    否则,如果您真的必须编辑age,那么它首先不能是val。使用反射你仍然可以调整值,但如果到这里的答案已经足够了,那么它们就是要走的路......

    对于更动态的方式,您可以使用以下方法(我仍然会针对copy-方法,因为这样您就不会意外更新当前对象):

    val person = Person("Morné", 25)
    val updates = mapOf("lastname" to "N/A", "age" to 22)
    
    val copiedPerson = with(person::class.memberFunctions.first { it.name == "copy" }) {
      callBy(mapOf(instanceParameter!! to person)
          .plus(updates.mapNotNull { (property, newValue) ->
            parameters.firstOrNull { it.name == property }
                ?.let { it to newValue }
          })
      )
    }
    println(copiedPerson)
    

    哪个打印:

    Person(name=Morné, age=22)
    

    如果您想继续使用实际类型,也可以在callBy 之后使用类似.let { person::class.cast(it } 的内容。如果您只希望它与Person 类型一起使用,您还可以将personPerson 交换,并将其直接转换为as Person

    【讨论】:

    • 我想要一个不需要我在编译时知道任何属性的解决方案。我以年龄为例,我的选择标准会更复杂。
    • 我想知道哪个用例需要这样的构造。在那之前,我会准备更新答案;-)
    • 更新了答案...让我知道这是否对您有帮助...或者您有任何疑问...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    相关资源
    最近更新 更多