Scala反射:如何将对象的方法作为参数传递给另一个方法

时间:2013-10-02 03:31:15

标签: scala reflection

假设我有两个班级:

class A {
  def sayHello(name: String) {
    println("Hi " + name)
  }  
}

class B {
  var methodMaps = Map[String, String => Unit]()
  def registerMethod(methodName: String, method: String => Unit) {
    methodMaps += (methodName -> method)
  }
}

好的,通常情况下,我会打电话给:

val b = new B
val a = new A
b.registerMethod("sayHello", a.sayHello)

但现在我想将信息放入配置文件中,例如:

<method class="A" name="sayHello" />

现在,在代码中它需要是这样的:

val b = new B
val className = readFromConfig()
val methodName = readFromConfig()
val aInstance = createInstanceFromReflection(className)
b.registerMethod(methodName, ...)

问题是我不知道如何让a.sayHello传递给registerMethod,我可以为sayHello获取MethodMirror,但是如何将它传递给registerMethod?

感谢。

1 个答案:

答案 0 :(得分:0)

我想在你的情况下,你需要简单的旧反思。在您的示例中,在表达式b.registerMethod("sayHello", a.sayHello)中,Scala编译器会将a.sayHello提升为函数。 当您使用文件中的动态类数据时,编译器无法帮助您;这意味着你需要自己做这项工作。按照你自己的例子,我们应该:

val className = readFromConfig()
val methodName = readFromConfig()
val clazz = Class.forName(className)
val method = clazz.getMethods.find(x=>x.getName == "methodName" && x.getParameterTypes().length==1)
val aInstance = clazz.newInstance()

def invoke1[T,U](obj:Any, method:Method)(param:T):U = method.invoke(obj,Seq(param.asInstanceOf[java.lang.Object]):_*).asInstanceOf[U]

现在你应该可以在你的地图中注册这样的构造:

registerMethod(methodName, invoke1(aInstance,method) _ )

(*)这未经过测试,但应该是正确的方向,我们在系统的某些部分使用类似的结构。