Почему мои отражающие сеттеры не меняют значения полей моего объекта? - PullRequest
0 голосов
/ 26 февраля 2019

Мой пример класса:

class Thing() {

  // Public vars
  var one: Int = 1
  var two: Int = 2

  // Scala-style getter/setter
  private var _age: Long = 3
  def age: Long = _age 
  def age_=(a: Long) = _age = a

  override def toString(): String = s"one: $one, two: $two, age: $age"
}

// A name -> setter holder class
case class Member(name:String, setter: MethodSymbol)

Теперь мой код отражения и инициатор установки:

  def analyze[T](classSymbol: ClassSymbol)(implicit tt:TypeTag[T]): List[Member] = {
    val tpe = tt.tpe
    val classMirror = currentMirror.reflectClass(classSymbol)

    tpe.members.filter(p => p.isPublic).collect {
      // Ignore the non-methods and methods we don't care about
      case (p) if (p.isMethod && tpe.member(TermName(p.name.toString + "_$eq")) != NoSymbol) =>
        val setter =
            // 1) Scala-stype getters/setters
            tpe.members.filter(f => f.name.toString == p.name.toString + "_" && f.isMethod).headOption.map(_.asMethod)
              // 2) Public var (no getter/setter)
              .orElse(tpe.members.filter(f => f.name.toString == p.name.toString).headOption.map(_.asMethod))
        Member(p.name.toString,setter.get)
    }.toList
  }

  def setValue[T](t:T, members: List[Member], field: String, value: Any)(implicit tt:TypeTag[T]) = {
    implicit val classTag = ClassTag[T](typeTag[T].mirror.runtimeClass(typeTag[T].tpe))
    members.find(_.name == field).map{ m =>
      println("--> Setting field "+m.name+" to "+value)
      currentMirror.reflect(t).reflectMethod(m.setter)(value)
    }
  }

И, наконец, моя попытка использования:

  val obj = new Thing()
  println("Before: "+obj)

  val members = analyze[Thing](currentMirror.classSymbol(obj.getClass()))
  println(members.mkString("\n"))

  // Now set some value on a public var
  setValue[Thing](obj, members, "one", 99)
  println("After: "+obj)

Вывод показывает:

Before: one: 1, two: 2, age: 3
Member(age,method age)
Member(two,variable two)
Member(one,variable one)
--> Setting field one to 99
After: one: 1, two: 2, age: 3

Как вы видите, отражение правильно различает поле getter / setter и общедоступное поле var.После попытки установить, он нашел поле и вызвал установщик без каких-либо исключений, но ... в моем объекте значение фактически не изменилось (это верно как для поля getter / setter, так и для полей var).Почему я не вижу изменения значения?

1 Ответ

0 голосов
/ 26 февраля 2019

Нашел это ... опубликовано на случай, если это поможет другим.

Я фильтровал не ту вещь.Сеттеры в Scala имеют имена, отформатированные как «foo_ $ eq», поэтому я должен искать этот шаблон.Когда эти методы вызываются, значения в классе экземпляра изменяются, как и ожидалось.Пересмотренный код отражения ниже:

  def analyze[T](classSymbol: ClassSymbol, isGetterSetter:Boolean = false)(implicit tt:TypeTag[T]): List[Member] = {
    val tpe = tt.tpe
    val Pattern = """(.*)_\$eq""".r

    tpe.members.filter(p => p.isPublic).collect {
      case p if (p.isMethod && p.name.toString.endsWith("_$eq")) =>
        val Pattern(name) = p.name.toString
        val setter =
            // 1) Scala-stype getters/setters
            tpe.members.filter(f => f.name.toString == p.name.toString + "_" && f.isMethod).headOption.map(_.asMethod)
              // 2) Public var (no getter/setter)
              .orElse(tpe.members.filter(f => f.name.toString == p.name.toString).headOption.map(_.asMethod))
        Member(name,setter.get)
    }.toList
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...