Kotlin:将不同目标对象的属性值与(out)反射进行比较

时间:2017-10-17 14:07:46

标签: reflection lambda kotlin

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

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

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

我可以以某种方式访问​​.name的属性函数并在另一个目标值(在此示例中在firstA上)上执行它而不显式定义它吗? 代表可以在这里提供帮助,或者我如何在有反射的情况下解决这个问题?

2 个答案:

答案 0 :(得分:3)

没有反思

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

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 val name: String, override val old : A? = null)
val firstA = A("hello")
val secondA = A("you", firstA)

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

这是基于lambda literals with receivers的概念,它允许Kotlin构建强大的构建器和DSL。

注意:DiffValue界面是可选的,仅用于使值更容易保持在一起并避免changed中的其他参数。

答案 1 :(得分:2)

使用反射

使用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))
}