Использование Dynamic для вызова перегруженного метода - PullRequest
3 голосов
/ 05 декабря 2011

В C # возможно использовать AsDynamic для вызова перегруженного метода в подклассе (пример здесь ), что позволяет абстрактному классу вызывать методы, которые он сам не определяет. Возможно ли нечто подобное в 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 и InventoryItemDeactivation оба являются событиями

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 ]

3 голосов
/ 06 декабря 2011

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. Но я подозреваю, что это не то, что вы хотите.

3 голосов
/ 05 декабря 2011

Я не совсем понимаю, что должен делать весь пример кода в ваших ссылках (AsDynamic() не является частью стандартного BCL), но, учитывая беглый взгляд на то, что вы отправили, я бы сказал, что ScalaДинамическая черта вам не поможет.

.NET dynamic позволяет вам (помимо прочего) иметь многократную отправку в c # .Если я не ошибаюсь, это то, что пытается сделать ваш пример, вызывая правильный handleEvent метод, основанный на типе времени выполнения аргумента event.

Динамическая черта Scala, вместо этого, не может (AFAIK) раньше делал это: это было предназначено для того, когда вам нужно / нужно вызвать метод, который не существует во время компиляции (что является одной из вещей, которые динамическая среда .NET позволяет вам делать, но, к сожалению, не то, что вам кажетсяв этом случае).

Например, Dynamic 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 вызовом applyDynamic("hello"))

...