2

假设我有 2 节课:

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?

谢谢。

4

1 回答 1

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) _ )

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

于 2013-10-02T08:05:57.920 回答