Kotlin通用二传手功能

时间:2018-08-30 03:00:24

标签: kotlin

我是科特林的新手。我想知道这是否可能

我希望创建一个函数,该函数将更改对象的属性值并返回对象本身。主要好处是我可以链接此设置器。

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请提供解释它的答案。谢谢

3 个答案:

答案 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"]
}

如果您还想摆脱吸气剂,则需要使用反射。