我想使用具有一些注释的所有属性的值。在大多数情况下,我的代码都有效,我得到了所有属性,只接受了那些带有注释的属性。
private inline fun <reified A : Annotation> (target: Any) {
target::class.memberProperties
.filter { it.annotations.any { annotation -> annotation is A } }
.forEach {
// How do I get the value here?
}
}
我想使用it.get(...)
,但get
需要Nothing
作为参数。同样适用于getter
。调用it.call(target)
确实有效但看起来不对,因为有一个我不知道如何调用的实际get
。
那么获取属性值的正确方法是什么?
答案 0 :(得分:6)
问题归结为T::class
为您提供了KClass<T>
,而t::class
为您提供了KClass<out T>
。请考虑以下事项:
class Foo {
val foo = 2
val bar = 3
}
fun f() {
val any: Any = Foo()
any::class.memberProperties.forEach {
println(it.get(2)) // Oops
}
}
这实际上会尝试访问2.foo
和2.bar
,但不允许这样做,因为get
在谨慎方面犯了错误,而不是允许Any
类型的参数1}}。但是,看起来t.javaClass.kotlin
会产生KClass<T>
。如上所述滥用它会导致IllegalArgumentException
。
您可以通过提供KClass
将为该类型而不是其他内容的编译时保证来为编译器提供更多帮助:
private inline fun <reified A : Annotation, reified T : Any> foo(target: T) {
T::class.memberProperties
.filter { it.annotations.any { annotation -> annotation is A } }
.forEach {
println(it.get(target))
}
}
很遗憾,我不知道从A
推断T
时是否可以指定target
。我还没有像foo<Attr, Bar>(bar)
那样找到一种方法。
或者,你可以浏览javaClass
,虽然我打赌它的便携性不足:
private inline fun <reified A : Annotation> foo(target: Any) {
target.javaClass.kotlin.memberProperties
.filter { it.annotations.any { annotation -> annotation is A } }
.forEach {
println(it.get(target))
}
}
我们知道这不会遇到上述问题,因为我们在两种情况下都传递相同的对象。这对于来电者来说也看起来更好,这可能值得携带,如果有的话。(/ p>