使用scala调用泛型类型的方法并反映包

时间:2016-06-14 08:01:23

标签: scala generics reflection

我的问题是基于我在以下页面上进行的搜索(但我仍然是scala的新成员,以便在我想做的事情上取得成功):

reflection overview

我的代码的目的是从泛型类型调用方法,而不是已知类型的实例。

以下说明了这个想法:

class A {
  def process = {
    (1 to 1000).foreach(x => x + 10)
  }
}

def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]

def perf[T: ru.TypeTag](t: T, sMethodName: String): Any = {
  val m = ru.runtimeMirror(t.getClass.getClassLoader)

  val myType = ru.typeTag[T].tpe

  val mn = myType.declaration(ru.newTermName(sMethodName)).asMethod

  val im = m.reflect(getTypeTag(t))

  val toCall = im.reflectMethod(mn)

  toCall()

}


val a = new A
perf(a, "process")

代码编译完美(在工作表上),但在执行时给出以下堆栈:

scala.ScalaReflectionException: expected a member of class TypeTagImpl, you provided method A$A11.A$A11.A.process
    at scala.reflect.runtime.JavaMirrors$JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$ErrorNotMember(test-log4j.sc:126)
    at scala.reflect.runtime.JavaMirrors$JavaMirror$$anonfun$scala$reflect$runtime$JavaMirrors$JavaMirror$$checkMemberOf$1.apply(test-log4j.sc:221)
    at scala.reflect.runtime.JavaMirrors$JavaMirror.ensuringNotFree(test-log4j.sc:210)
    at scala.reflect.runtime.JavaMirrors$JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$checkMemberOf(test-log4j.sc:220)
    at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaInstanceMirror.reflectMethod(test-log4j.sc:257)
    at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaInstanceMirror.reflectMethod(test-log4j.sc:239)
    at #worksheet#.perf(test-log4j.sc:20)
    at #worksheet#.get$$instance$$res0(test-log4j.sc:28)
    at #worksheet#.#worksheet#(test-log4j.sc:138)

有关如何纠正此问题的任何想法?

非常感谢所有

1 个答案:

答案 0 :(得分:1)

为了反映特定对象,您必须将其传递给Mirror.reflect(obj: T),并且由于某种原因您传递了typeTag。要解决此问题,您必须修改perf签名以生成ClassTagTypeTag,并将t直接传递给reflect,如下所示:

class A {
  def process = {
    (1 to 1000).foreach(x => x + 10)
    println("ok!")
  }
}

def perf[T : ClassTag : ru.TypeTag](t: T, sMethodName: String): Any = {
//         ^ modified here
  val m = ru.runtimeMirror(t.getClass.getClassLoader)
  val myType = ru.typeTag[T].tpe
  val mn = myType.decl(ru.TermName(sMethodName)).asMethod
  val im = m.reflect(t)
//                   ^ and here
  val toCall = im.reflectMethod(mn)
  toCall()
}


val a = new A
perf(a, "process")
// ok!
// res0: Any = ()

(注意:我还用推荐的替代品替换了已弃用的declarationnewTermName