Kotlin reify 未获取实际实例类型

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

我正在尝试使用 Kotlin 和 DDD 实现 ValueObject 基类。由于任何值对象都必须考虑 equals 方法中的所有属性,因此我决定使用反射实现单个方法,因此不需要子类来实现它。

我的ValueObject类如下:

abstract class ValueObject {
    override fun equals(other: Any?) = when {
        this === other -> true
        other !is ValueObject -> false
        else -> deepEquals(other)
    }

    inline fun <reified T : Any> deepEquals(other: T): Boolean {
        val fields = T::class.java.declaredFields

        println(T::class)

        for (field in fields) {
            field.isAccessible = true
            val thisValue = field.get(this)
            val otherValue = field.get(other)
            if (thisValue != otherValue && (thisValue == null || !thisValue.equals(otherValue))) {
                return false
            }
        }
        return true
    }

    override fun hashCode() = hashFromReflection()

    private fun hashFromReflection(): Int {
        val fields = this::class.java.declaredFields
        var result = 17

        for (field in fields) {
            field.isAccessible = true
            val value = field.get(this)
            result = 31 * result + (value?.hashCode() ?: 0)
        }

        return result
    }

    protected abstract fun validate() : Notification
}

我实现了以下代码来测试:

class PhoneNumber (val code: String, val number: String) : ValueObject() {
    override fun validate(): Notification {
        return Notification()
    }
}

fun main() {
    val phoneNumber = PhoneNumber("33", "w")
    val other = PhoneNumber("3", "w")
    println(phoneNumber == other)
    println(phoneNumber.deepEquals(other))
}

然而,结果很奇怪。如果我直接调用 deepEquals ,它工作得很好。但如果我使用 == 运算符,它会将 T 视为 ValueObject(而不是 PhoneNumber),找不到声明的字段,并给出错误的结果:

class br.all.domain.common.ValueObject
true
class br.all.domain.common.PhoneNumber
false

我做错了什么?

kotlin generics reflection domain-driven-design reify
1个回答
0
投票

你似乎用

reified
使这件事变得过于复杂。您可以通过执行
Class
this::class.java
来获取对象的
other::class.java
。不需要
reified

override fun equals(other: Any?): Boolean {
    if (this === other) return true
    // note that you should also check this::class.java != other::class.java!
    if (other == null || this::class.java != other::class.java) return false

    val fields = other::class.java.declaredFields

    for (field in fields) {
        field.isAccessible = true
        val thisValue = field.get(this)
        val otherValue = field.get(other)
        if (thisValue != otherValue && (thisValue == null || !thisValue.equals(otherValue))) {
            return false
        }
    }
    return true
}

您的代码不起作用的原因是,当您在

ValueObject
中调用
deepEquals(other)
时,没有关于
equals
特定子类的类型信息。具体化类型参数只是作为
deepEquals<ValueObject>(other)
传递。

此外,您似乎正在重新发明数据类。考虑使用数据类来执行此操作。

abstract class ValueObject {
    protected abstract fun validate(): Notification
}

data class PhoneNumber (val code: String, val number: String) : ValueObject() {
    override fun validate(): Notification {
        // ...
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.