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 un object Kotlin por su nombre?
  • Obteniendo la class actual
  • Kotlin enlazó la incoinheritance de las references invocables
  • ¿Cómo get la reference de class de KParameter en kotlin?
  • ¿Cómo get una KClass de Array?
  • ¿Cómo obtengo las funciones declaradas de una class Kotlin (KClass en M12)?
  • ¿Es seguro llamar a kclass.memberProperties en un object desconocido (Cualquiera)?
  • ¿Cómo puedo get una reference a Kotlin KClass por nombre cuando no se ejecuta en la JVM?
  • Cómo acceder a los objects-miembros de una statement de object en kotlin
  • ¿Puedo usar kotlin.reflect para get un valor de un campo
  • ¿Cómo obtengo una KProperty1 de una KProperty0?