Проблема при использовании концепции класса отражения в scala

У меня есть один такой главный класс:

class Test {
  def exe(first:String, second:String, task:String):String = {
     task match {
       case "A" => {
          val obj = new A(first)
          obj.defineSecond(second)
       }
       case "B" => {
          val obj = new B(first)
          obj.defineSecond(second)
       }
       case "C" => {
          val obj = new C(first)
          obj.defineSecond(second)
       }
       ....so many cases
   }
 }
}

Вместо того, чтобы писать case в моем тестовом классе каждый раз, когда добавляется новый класс, я пробовал использовать концепцию отражения в scala. Вот что я пробую:

val m = ru.runtimeMirror(getClass.getClassLoader)
val classTest = ru.typeOf[Test].typeSymbol.asClass
val cm = m.reflectClass(classTest)

Но возникает ошибка, так как class Test является внутренним классом, используйте RefleClass в InstaneMirror, чтобы получить его classMirror.

Может ли кто-нибудь знать, как я могу избежать добавления кейсов в мой основной класс каждый раз, когда создается новый класс, вместо этого я могу написать свой основной класс таким образом, чтобы он работал для каждого случая.


person Sunny Arora    schedule 31.08.2020    source источник
comment
Если честно, я бы просто сохранил матч. Или вы можете использовать Enumeratum, чтобы определить все свои задачи и таким образом легко построить карту от имени к задаче.   -  person Luis Miguel Mejía Suárez    schedule 31.08.2020
comment
Отражение времени выполнения редко бывает подходящим решением   -  person cchantep    schedule 31.08.2020


Ответы (1)


Думаю, вы не предоставили всю необходимую информацию в своем вопросе. В сообщении об ошибке написано, что класс Test является внутренним классом, но Test не является внутренним в фрагменте кода. Если вы хотите, чтобы код отражения времени выполнения был исправлен, предоставьте фрагмент кода, который отражает реальный вариант использования.

А пока вы можете попробовать макрос (работающий во время компиляции)

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

class Test {
  def exe(first: String, second: String, task: String): String = macro Test.exeImpl
}

object Test {
  def exeImpl(c: blackbox.Context)(first: c.Tree, second: c.Tree, task: c.Tree): c.Tree = {
    import c.universe._
    val cases = Seq("A", "B", "C").map(name =>
      cq"""${Literal(Constant(name))} => {
        val obj = new ${TypeName(name)}($first)
        obj.defineSecond($second)
      }"""
    )
    q"$task match { case ..$cases }"
  }
}

Использование:

class A(s: String) {
  def defineSecond(s1: String): String = ""
}
class B(s: String) {
  def defineSecond(s1: String): String = ""
}
class C(s: String) {
  def defineSecond(s1: String): String = ""
}

new Test().exe("first", "second", "task")

//scalac: "task" match {
//  case "A" => {
//    val obj = new A("first");
//    obj.defineSecond("second")
//  }
//  case "B" => {
//    val obj = new B("first");
//    obj.defineSecond("second")
//  }
//  case "C" => {
//    val obj = new C("first");
//    obj.defineSecond("second")
//  }
//}
person Dmytro Mitin    schedule 31.08.2020
comment
Спасибо!! Мое фактическое определение класса такое же, как только Test. А случай «А», «В» - не что иное, как класс правил. И имя вызываемого класса правил находится в Task: String и сначала содержит фактические данные, к которым я должен применить правило. Каждый раз, когда я реализую новый класс, мне приходится добавлять и его класс Test, поэтому нужно, чтобы эта вещь была динамической, чтобы можно было удалить повторяющийся код, потому что все случаи почти одинаковы, за исключением имени класса. - person Sunny Arora; 31.08.2020
comment
@SunnyArora Еще раз, в вашем фрагменте кода Test не является внутренним. Это на самом деле внутреннее? Затем предоставьте фрагмент кода, где он находится внутри. - person Dmytro Mitin; 31.08.2020