【发布时间】:2020-05-05 05:23:24
【问题描述】:
给定一个包含一堆成员的类,我想合并它的两个实例。结果实例应保留两个输入中的每一个的非空值。如果两个非空值相互矛盾,则应引发异常。
我当前的实现有些效果,但扩展性不好:
import kotlin.reflect.KProperty1
import kotlin.reflect.full.memberProperties
import kotlin.test.fail
class Thing(
val a: Int,
var b: String,
val c: Int? = null,
val d: Boolean? = null,
val e: Long? = null,
val f: String? = null,
val g: String? = null
)
private fun <T> mergeThingProperty(property: KProperty1<Thing, *>, a: Thing, b: Thing): T {
val propA = property.get(a)
val propB = property.get(b)
val mergedValue = if (propA != null && propB == null) {
propA
} else if (propA == null && propB != null) {
propB
} else if (propA != null && propB != null) {
if (propA != propB) {
throw RuntimeException("Can not merge Thing data on property ${property.name}: $propA vs. $propB.")
} else {
propA
}
} else {
null
}
@Suppress("UNCHECKED_CAST")
return mergedValue as T
}
fun mergeTwoThings(thing1: Thing, thing2: Thing): Thing {
val properties = Thing::class.memberProperties.associateBy { it.name }
val propertyMissingMsg = "Missing value in Thing properties"
return Thing(
mergeThingProperty(properties["a"] ?: error(propertyMissingMsg), thing1, thing2),
mergeThingProperty(properties["b"] ?: error(propertyMissingMsg), thing1, thing2),
mergeThingProperty(properties["c"] ?: error(propertyMissingMsg), thing1, thing2),
mergeThingProperty(properties["d"] ?: error(propertyMissingMsg), thing1, thing2),
mergeThingProperty(properties["e"] ?: error(propertyMissingMsg), thing1, thing2),
mergeThingProperty(properties["f"] ?: error(propertyMissingMsg), thing1, thing2),
mergeThingProperty(properties["g"] ?: error(propertyMissingMsg), thing1, thing2)
)
}
fun main() {
val result1 = mergeTwoThings(Thing(a = 42, b = "foo"), Thing(a = 42, b = "foo", c = 23))
assert(result1.c == 23)
assert(result1.d == null)
try {
mergeTwoThings(Thing(a = 42, b = "foo"), Thing(a = 42, b = "bar"))
fail("An exception should have been thrown.")
} catch (ex: RuntimeException) {
}
}
如何避免手动重复每个成员(目前在mergeTwoThings)?
另外,如果我不需要未经检查的演员表(目前在mergeThingProperty),那就太好了。
【问题讨论】:
标签: class generics kotlin reflection null