如何使用kotlin和refelction迭代嵌套数据类

如何使用kotlin和refelction迭代嵌套数据类,kotlin,reflection,Kotlin,Reflection,我有一个名为report的数据类,它本质上是一个变量列表的列表,即嵌套的数据类 data class report( var list1 : List1, var list2 : List2 ) : Parcelable data class List1 ( var a: Boolean = false, var b: Boolean = false, ) : Parcelable data class List2 ( var c : Boolea

我有一个名为report的数据类,它本质上是一个变量列表的列表,即嵌套的数据类

data class report(
    var list1 : List1,
    var list2 : List2
) : Parcelable

data class List1 (
    var a: Boolean = false,
    var b: Boolean = false,
) : Parcelable 


data class List2 (
    var c : Boolean = false,
    var d : Boolean = false,
) : Parcelable 
使用Kotlin和reflection,我有一个for循环,它迭代顶级数据类,并成功地打印变量的名称。我想迭代每个嵌套类并打印变量名称,但如果不按名称显式引用嵌套类,我就无法知道如何执行该操作。第一个for循环打印正确的数据,而第二个for循环只打印“长度”


在第二个循环中,我感觉“prop”没有被正确地扩展为对嵌套类的引用。我尝试了“report.prop.name”或“report.${prop.name}”之类的方法,但没有成功。我还尝试将report.prop.name分配给一个单独的变量。这是一个我不知道的简单语法问题吗?我确实读过Stack上的其他类似问题,但没有找到解决方案。这可能与没有在适当的时候创建类实例有关吗?

问题是,您试图迭代可能不同类型的属性,因此反射无法知道顶层之后是什么类型

report::class.declaredMemberProperties
返回包含
KMutableProperty1
对象的集合。无法派生
KMutableProperty1
的泛型类型,因为泛型会被擦除,因此可能是任何类型。当然,知道它们是
KMutableProperty1
KMutableProperty1
,但是您在编译时使用泛型来查看它。反射必须在运行时动态执行,而不使用泛型,因此在使用反射时,您只知道类型为
KMutableProperty1

我相信这意味着无法动态循环您所描述的属性,因为属性类型在运行时是未知的。唯一的方法是显式地声明每个属性的类型,但这有点违背了这一点:

fun <T : Any> KClass<T>.printPropertyNames(): Unit {
    for (prop in declaredMemberProperties) {
        println("$this: ${prop.name}")
    }
}

fun main() {
    Report::class.printPropertyNames()
    for (prop in Report::class.declaredMemberProperties) {
        when (prop.name) {
            "list1" -> List1::class.printPropertyNames()
            "list2" -> List2::class.printPropertyNames()
        }
    }
}
但是,如果您只想查看对象中的内容,可以使用数据类的默认
toString()
行为:

println(Report(List1(true, false), List2(false, true)))
输出:

class Report: list1
class Report: list2
class List1: a
class List1: b
class List2: c
class List2: d
Report(list1=List1(a=true, b=false), list2=List2(c=false, d=true))

问题是,您试图迭代可能不同类型的属性,因此反射无法知道顶级之后的类型是什么

report::class.declaredMemberProperties
返回包含
KMutableProperty1
对象的集合。无法派生
KMutableProperty1
的泛型类型,因为泛型会被擦除,因此可能是任何类型。当然,知道它们是
KMutableProperty1
KMutableProperty1
,但是您在编译时使用泛型来查看它。反射必须在运行时动态执行,而不使用泛型,因此在使用反射时,您只知道类型为
KMutableProperty1

我相信这意味着无法动态循环您所描述的属性,因为属性类型在运行时是未知的。唯一的方法是显式地声明每个属性的类型,但这有点违背了这一点:

fun <T : Any> KClass<T>.printPropertyNames(): Unit {
    for (prop in declaredMemberProperties) {
        println("$this: ${prop.name}")
    }
}

fun main() {
    Report::class.printPropertyNames()
    for (prop in Report::class.declaredMemberProperties) {
        when (prop.name) {
            "list1" -> List1::class.printPropertyNames()
            "list2" -> List2::class.printPropertyNames()
        }
    }
}
但是,如果您只想查看对象中的内容,可以使用数据类的默认
toString()
行为:

println(Report(List1(true, false), List2(false, true)))
输出:

class Report: list1
class Report: list2
class List1: a
class List1: b
class List2: c
class List2: d
Report(list1=List1(a=true, b=false), list2=List2(c=false, d=true))

所以我用一个函数和一个for循环做到了这一点,如下所示:

fun <T> printProperty(instance: T, prop: KProperty1<T, *>): Any? {
        println("${prop.name} = ${prop.get(instance)}")
        return prop.get(instance)
    }

for (rep in MyReport::class.memberProperties) {
        val reportProperty = MyReport::class.memberProperties.single{ it.name == rep.name}
        val reportInstance = printProperty(report, reportProperty)
        for (subRep in reportInstance!!::class.memberProperties) {
            println("${subRep.name} = ${subRep.getter.call(reportInstance)}")
            }
        }
fun printProperty(实例:T,属性:KProperty1):有吗?{
println(${prop.name}=${prop.get(实例)}”)
返回prop.get(实例)
}
for(MyReport::class.memberProperties中的代表){
val reportProperty=MyReport::class.memberProperties.single{it.name==rep.name}
val reportInstance=printProperty(报告,reportProperty)
对于(reportInstance!!::class.memberProperties中的子代表){
println(${subRep.name}=${subRep.getter.call(reportInstance)}”)
}
}

我不知道为什么,但我不能在第二次for循环中再次使用我的函数-相反,我必须使用getter.call来获得我想要的值。

所以我用一个函数和一个for循环做到了这一点,就像这样:

fun <T> printProperty(instance: T, prop: KProperty1<T, *>): Any? {
        println("${prop.name} = ${prop.get(instance)}")
        return prop.get(instance)
    }

for (rep in MyReport::class.memberProperties) {
        val reportProperty = MyReport::class.memberProperties.single{ it.name == rep.name}
        val reportInstance = printProperty(report, reportProperty)
        for (subRep in reportInstance!!::class.memberProperties) {
            println("${subRep.name} = ${subRep.getter.call(reportInstance)}")
            }
        }
fun printProperty(实例:T,属性:KProperty1):有吗?{
println(${prop.name}=${prop.get(实例)}”)
返回prop.get(实例)
}
for(MyReport::class.memberProperties中的代表){
val reportProperty=MyReport::class.memberProperties.single{it.name==rep.name}
val reportInstance=printProperty(报告,reportProperty)
对于(reportInstance!!::class.memberProperties中的子代表){
println(${subRep.name}=${subRep.getter.call(reportInstance)}”)
}
}

我不知道为什么,但我不能在second for循环中再次使用我的函数-相反,我必须使用getter.call来获得我想要的值。

谢谢Adam。这是否解释了为什么我不能使用抽象函数引用嵌套类?类似于:
println(report.prop.name)
问题在于
prop
KMutableProperty1
,因此
subop
表示
KMultableProperty1
类的属性,而不是
List1
List2
等。谢谢Adam。这是否解释了为什么我不能使用抽象函数引用嵌套类?类似于:
println(report.prop.name)
问题在于
prop
KMutableProperty1
,因此
subop
表示
KMultableProperty1
类的属性,而不是
List1
List2
,等等。