Kotlin: comparar los valores de propiedad de diferentes objects objective con (fuera) reflexión

Quiero comparar valores entre varias instancias de una class de datos para saber qué valor cambió:

data class A(val name : String) val firstA = A("hello") val secondA = A("you") if (secondA.name.changed(firstA)) { // Do something } 

¿Puedo de alguna manera acceder a la function de propiedad de .name y ejecutarla en otro valor objective (en este ejemplo en firstA) sin definirlo explícitamente? ¿Pueden los delegates ayudar aquí o cómo puedo resolver esto con y sin reflexión?

Usando la reflexión

Utilizando la biblioteca de reflexión de Kotlin puede usar memberProperties y filtrar por diferentes valores

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

Salida

 b c 

No usando la reflexión

Necesita repasar explícitamente cada método (o almacenarlos en una list e iterar sobre ellos)

Sin list

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

Con list

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

Sin Reflexión

Encontré una manera sin usar la reflexión:

 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 } 

Y así es como lo usas:

 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 } 

Esto se basa en el concepto de literales lambda con receptores que permiten a Kotlin build constructores y DSL potentes.

Nota: La interfaz DiffValue es opcional y solo se usa para facilitar un poco los valores y evita la changed un parámetro adicional.

  • ¿Cómo puedo get una reference a Kotlin KClass por nombre cuando no se ejecuta en la JVM?
  • Kotlin comtesting si la function requiere parámetro de instancia
  • Usar reflexión para pasar y modificar una primitiva sin usar matriz
  • ¿Cómo obtengo una KProperty1 de una KProperty0?
  • Kotlin obtiene la anotación de campo siempre vacía
  • Verificar si la function es extensión
  • La igualdad de class Kotlin falla
  • Kotlin, cómo recuperar el valor del campo a través de la reflexión
  • por qué SomeClass :: class es KClass <SomeClass> pero esta :: class es KClass <out SomeClass>
  • ¿Cómo hacer inferencia tipo Kotlin desde la reflexión KClass?
  • Quiero detectar si una class JVM es una class Kotlin o no