Kotlin:通过(out)反射比较不同目标对象的属性值

问题描述 投票:0回答:2

我想比较数据类的多个实例之间的值,以便我知道哪个值发生了变化:

data class A(val name : String)
val firstA = A("hello")
val secondA = A("you")

if (secondA.name.changed(firstA)) {
   // Do something
}

我可以以某种方式访问

.name
的属性函数并在另一个目标值上执行它(在本例中是在firstA 上)而不显式定义它吗? 代表们可以在这里提供帮助吗?或者我如何通过反思或不反思来解决这个问题?

reflection lambda kotlin
2个回答
11
投票

无反射

我找到了一种不使用反射的方法:

interface DiffValue<T> {
    val old : T?
}

fun <T,R> T.changed(memberAccess : T.() -> R) : Boolean {
    if (this is DiffValue<*>) {
        val old = this.old as? T
        if (old != null) {
            val currentValue = with(this, memberAccess)
            val previousValue = with(old, memberAccess)
            return currentValue != previousValue
        }
    }
    return true
}

这就是你如何使用它:

data class A(val name: String, override val old : A? = null): DiffValue<A>
val firstA = A("hello")
val secondA = A("you", firstA)

if (secondA.changed {name}) {
   // Do something
}

这是基于 带有接收器的 lambda 文字的概念,它允许 Kotlin 构建强大的构建器和 DSL。

注意:

DiffValue
接口是可选的,只是用于更容易地将值保存在一起,并避免在
changed
中添加额外参数。


7
投票

使用反射

使用 Kotlin 反射库,您可以使用

memberProperties
并按不同值进行过滤

import java.util.*
import kotlin.reflect.full.memberProperties

data class Example(val a: Int, val b:Long, val c: String)

fun main(args: Array<String>) {
    val start = Example(1,2, "A")
    val end = Example(1,4, "B")
    val differentFields = Example::class.memberProperties.filter {
        val startValue = it.get(start)
        val endValue = it.get(end)
        !Objects.equals(startValue, endValue)
    }

    differentFields.forEach {
        println(it.name)
    }
}

输出

b
c

不使用反射

您需要显式地检查每个方法(或将它们存储在列表中并迭代它们)

无列表

import java.util.*

data class Example(val a: Int, val b:Long, val c: String) {
    fun getChanged(other: Example): List<String> {
        val ret: MutableList<String> = mutableListOf()

        if (!Objects.equals(a, other.a)) ret.add("a")
        if (!Objects.equals(b, other.b)) ret.add("b")
        if (!Objects.equals(c, other.c)) ret.add("c")

        return ret
    }
}

fun main(args: Array<String>) {
    val start = Example(1,2, "A")
    val end = Example(1,4, "B")
    println(start.getChanged(end))
}

带列表

import java.util.*

data class Example(val a: Int, val b:Long, val c: String) {

    data class Field(val function: (Example) -> Any?, val name: String)
    val fields: List<Field> = listOf(
            Field({ it.a }, "a"),
            Field({ it.b }, "b"),
            Field({ it.c }, "c")
    )

    fun getChanged(other: Example): List<String> {
        return fields.filter {
            !Objects.equals(it.function(this), it.function(other))
        }.map { it.name }
    }
}

fun main(args: Array<String>) {
    val start = Example(1,2, "A")
    val end = Example(1,4, "B")
    println(start.getChanged(end))
}
© www.soinside.com 2019 - 2024. All rights reserved.