Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin数据类:如果我没有';我在编译时不知道它的名字?_Kotlin_Data Class - Fatal编程技术网

Kotlin数据类:如果我没有';我在编译时不知道它的名字?

Kotlin数据类:如果我没有';我在编译时不知道它的名字?,kotlin,data-class,Kotlin,Data Class,如果只有在运行时才知道属性名,那么如何读取Kotlin数据类实例中属性的值呢?您可以完成这项工作,对于数据类和普通数据类都是一样的 第一种选择是只使用Java反射: val name = obj.javaClass .getMethod("getName") // to get property called `name` .invoke(obj) 您甚至可以创建一个扩展函数: inline fun <reified T : Any

如果只有在运行时才知道属性名,那么如何读取Kotlin数据类实例中属性的值呢?

您可以完成这项工作,对于数据类和普通数据类都是一样的

第一种选择是只使用Java反射:

val name = obj.javaClass
              .getMethod("getName") // to get property called `name`
              .invoke(obj)
您甚至可以创建一个扩展函数:

inline fun <reified T : Any> Any.getThroughReflection(propertyName: String): T? {
    val getterName = "get" + propertyName.capitalize()
    return try {
        javaClass.getMethod(getterName).invoke(this) as? T
    } catch (e: NoSuchMethodException) {
        null
    }
}

第二个选项涉及使用应该单独添加到项目中的库。它将让您获得实际的Kotlin属性值,而忽略Java getter

您可以使用
javaClass.kotlin
获取实际的kotlin类令牌,然后从中获取属性:

val name = p.javaClass.kotlin.memberProperties.first { it.name == "name" }.get(p)

此解决方案仅适用于Kotlin类,而不适用于Java类,但如果需要使用Kotlin类,则更可靠:它不依赖于底层实现。

这里有一个函数,用于从给定属性名称的类实例中读取属性(如果未找到属性,则引发异常,但您可以更改该行为):

导入kotlin.reflect.KProperty1
导入kotlin.reflect.full.memberProperties
@抑制(“未选中的_CAST”)
fun readInstanceProperty(实例:Any,属性名称:String):R{
val属性=实例::class.members
//不要投到这里,它会默默地成功
.first{it.name==propertyName}作为KProperty1
//如果此处的类型不正确,则强制执行无效的强制转换异常
返回property.get(实例)作为R
}
build.gradle.kts
依赖项{
实施(kotlin(“反映”))
}

使用
//某个数据类
数据类MyData(val名称:String,val年龄:Int)
val样本=我的数据(“Fred”,33)
//从实例中读取属性“name”。。。
val名称:String=readInstanceProperty(示例,“名称”)
//并读取属性“age”,将类型放置在函数调用上。。。
val age=readInstanceProperty(示例,“age”)
println(name)//Fred
println(年龄)//33

上面的答案对我不起作用,因此我为此创建了一个扩展函数:

@Throws(IllegalAccessException::class, ClassCastException::class)
inline fun <reified T> Any.getField(fieldName: String): T? {
    this::class.memberProperties.forEach { kCallable ->
        if (fieldName == kCallable.name) {
            return kCallable.getter.call(this) as T?
        }
    }
    return null
}

我想知道是否有可能以编程方式定义字段的类型。您可以使用以下工具轻松获得该类型:

kCallable.returnType
但是,您仍然必须明确指定泛型类型:

getField<String>
getField
而不是

getField<kCallable.returnType>
getField
编辑: 我最终使用了以下方法:

when (prop.call(object)) {
    is ObservableList<*> -> {}
    is Property<*> -> {}
}
何时(属性调用(对象)){
是可观察列表->{}
是属性->{}
}

Kotlin有一个反射库:答案中有使用@jbnitet提到的类的示例嘿@Elifarley检查我的答案:第一个解决方案有几个流:它排除继承的属性,不使用布尔属性(其getter以is开头…),尝试访问属性,即使它们不是公共的也许是个更好的主意。@JBNizet,谢谢你的评论,我会尝试改进一点。@JBNizet,修复了你所说的关于实现的内容。@JBNizet,嗯,刚刚尝试过——Kotlin为
布尔属性生成
getSomething
命名方法,而不是
isSomething
。这是我的观点的一部分:而不是assu如果您使用的是低级方法,那么您最好使用Kotlin反射支持的属性(即答案的第二部分)或者在处理Java bean的更高级别Java抽象中。我知道这个答案已经有2年了……这仍然是解决问题的方法吗?我很好奇,Kotlin API中是否添加了新的内容,这可能会创建另一种实现方法。@HatemJaber,如果您正在阅读一个不知道com名称的属性堆积时间,则为“是”。如果要读取编译时存在的已知属性,可以使用属性引用访问该属性。@HatemJaber:反射库的较新版本允许使用
instance::class.members
而不是
instance.javaClass.kotlin.declaredMemberProperties,但应检查属性的类型为
KProperty`或
KMutableProperty
@HatemJaber请检查我的答案:可能会有帮助you@AdamKis如果添加了正确的导入语句,我的答案仍然有效,我已将其更新为新版本并包含了导入。我相信Kotlin团队正在尝试将该语言与已检查的异常隔开。D你能找到答案吗?这正是我现在要处理的。
getField<String>
getField<kCallable.returnType>
when (prop.call(object)) {
    is ObservableList<*> -> {}
    is Property<*> -> {}
}