我是科特林的新手。我想知道这是否可能
我希望创建一个函数,该函数将更改对象的属性值并返回对象本身。主要好处是我可以链接此设置器。
class Person {
var name:String? = null
var age:Int? = null
fun setter(propName:String, value:Any): Person{
return this.apply {
try {
// the line below caused error
this[propName] = value
} catch(e:Exception){
println(e.printStackTrace())
}
}
}
}
//usage
var person = Person(null,null)
person
.setter(name, "Baby")
.setter(age, 20)
但是我收到错误消息“未知引用”
此问题被标记为重复,但是可能的重复问题专门想要更改“名称”的属性,但是我希望更改从函数传递给对象的anyProperty。似乎无法将两个问题联系起来。 @Moira请提供解释它的答案。谢谢
答案 0 :(得分:5)
为什么不只是简化您的答案
fun setter(propName: String, value: Any): Person {
val property = this::class.memberProperties.find { it.name == propName }
when (property) {
is KMutableProperty<*> ->
property.setter.call(this, value)
null ->
// no such property
else ->
// immutable property
}
}
不需要Java反射,它的唯一作用是停止支持非平凡的属性。
此外,如果您将其命名为operator fun set
而不是fun setter
,则
this[propName] = value
语法可以用来调用它。
答案 1 :(得分:2)
在谷歌搜索之后,我想我可以提供一个答案,但是纯粹依靠java而不是kotlin。如果有人可以在Kotlin中提供更好的答案,那就太好了。
class Person(
var name: String,
val age: Int
){
fun setter(propName: String, value: Any): Person{
var isFieldExistAndNotFinal = false
try{
val field = this.javaClass.getDeclaredField(propName)
val isFieldFinal = (field.getModifiers() and java.lang.reflect.Modifier.FINAL == java.lang.reflect.Modifier.FINAL)
if(!isFieldFinal) {
// not final
isFieldExistAndNotFinal = true
}
// final variable cannot be changed
else throw ( Exception("field '$propName' is constant, in ${this.toString()}"))
} catch (e: Exception) {
// object does not have property
println("$e in ${this.toString()}")
}
if(isFieldExistAndNotFinal){
val property = this::class.memberProperties.find { it.name == propName }
if (property is KMutableProperty<*>) {
property.setter.call(this, value)
}
}
return this;
}
}
这种用法
person
.setter(propName = "age", value = 30.00)
.setter(propName = "asdf", value = "asdf")
.setter(propName = "name", value = "A Vidy")
答案 2 :(得分:1)
您有错误,因为您在进行this[propName] = value
时尝试将this
用作列表,但它不是列表,而是Person
并且不会重载[]
运算符。
您可以做的是添加对设置的属性的检查:
class Person {
privavar name:String? = null
var age:Int? = null
fun setter(propName:String, value:Any): Person{
return this.apply {
if (propName == "name" && value is String?) {
it.name = value as String?
} else if (propName == "age" && value is Int?) {
it.age = value as Int?
} else {
// handle unknown property or value has incorrect type
}
}
}
}
另一种无需反思的动态解决方案:
class Person {
private var fields: Map<String, Any?> = HashMap()
fun setter(propName:String, value:Any): Person{
return this.apply {
it.fields[propName] = value;
}
}
fun getName() = fields["name"]
}
如果您还想摆脱吸气剂,则需要使用反射。