使用Dynamic调用重载方法

时间:2011-12-05 01:46:38

标签: scala dynamic

在C#中,它可能使用AsDynamic来调用子类上的重载方法(例如here),从而允许抽象类调用它本身不定义的方法。 Scala 2.9 applyDynamic 可能类似吗?我尝试了以下

abstract class AggregateRoot extends Dynamic {
  def applyChange(event: Event) {
    this.applyDynamic("handleEvent")(event) 
  }
  // this does not work
  def applyDynamic(name : String)(args: Any*) = this
}

像这样使用

class InventoryItem extends AggregateRoot {
  def handleEvent(event: InventoryItemCreated) {
    println("received InventoryItemCreated")
  }

  def handleEvent(event: InventoryItemDeactivated) {
    println("received InventoryItemDeactivated")
  }
}

其中 InventoryItemCreated InventoryItemDeactivated 都是事件

class Event;

class InventoryItemDeactivated extends Event; 

class InventoryItemCreated extends Event; 

然后我希望能够做这样的事情

  var aggregate : AggregateRoot = new InventoryItem
  var event = new InventoryItemDeactivated
  aggregate.applyChange(event) // should print "received InventoryItemDeactivated"

但我无法弄清楚如何定义 applyDynamic (在 AggregateRoot 中),以便它可以在运行时调用子类中的重载方法,而无需自己定义它们。其他获得相同结果的解决方案也是受欢迎的(也许结构化打字会派上用场?)。

2 个答案:

答案 0 :(得分:3)

我不完全理解链接中的所有示例代码应该做什么(AsDynamic()不是标准BCL的一部分)但是粗略地看一下你发送的内容,我会说scala的动态特性对你没有帮助。

.NET dynamic允许您(除其他外)拥有multiple dispatch in c#。如果我没有弄错,这就是你的例子试图做的,根据handleEvent参数的运行时类型调用正确的event方法。

相反,Scala的动态特性不能(AFAIK)用于执行此操作:它适用于您需要/想要调用在编译时不存在的方法(这是.NET的动态之一)允许你也这样做,但遗憾的是在这种情况下你不需要这样做。)

E.g。 scala的动态是做这样的事情:

scala> class Foo extends Dynamic {
     | def applyDynamic(name: String)(args: Any*) = name
     | }
defined class Foo

scala> new Foo
res0: Foo = Foo@17757ad

scala> res0.hello
dynatype: $line2.$read.$iw.$iw.res0.applyDynamic("hello")()
res1: String = hello  

(因为Foo没有“hello”方法,但它扩展了Dynamic特征,scala的编译器通过调用{来取代对hello的调用{1}})

答案 1 :(得分:3)

Dynamic在这里没有得到任何东西,因为它让定义了处理未定义方法的机制。但是,在您的示例中,所有调用的方法都已定义。

你真正想要的是找到在类中定义的方法的机制,而这不存在,因为Dynamic意味着成为其他JVM语言的桥梁,以完全不同的方式实施他们的“方法”。

然而,您需要做的就是使用反射。从2.9.1开始,Scala没有反射库,但是Java足够好用于此目的。这是你写AggregateRoot的方式:

abstract class AggregateRoot {
    def applyChange(event: Event) {
        this.getClass.getMethod("handleEvent", event.getClass).invoke(this, event)
    }
}

Dynamic允许您做的是:

abstract class AggregateRoot extends Dynamic {
    def applyDynamic(name : String)(args: Any*) = 
        this
        .getClass
        .getMethod(name, args map (_.getClass): _*)
        .invoke(this, args map (_.asInstanceOf[Object]): _*)
}

然后在最后这样做:

aggregate.handleEvent(event)

aggregate位于AggregateRoot,因为它属于InventoryItem而非handleEvent,但不知道它有方法{{1}}。但我怀疑这不是你想要的。

相关问题