NETJVM 

デリゲートとイベント

デリゲート システムは、オブジェクト指向において手続きポインターに相当する、型の安全性を保ったソリューションである。手続きポインターまたは関数ポインターは、多くの言語で一般的に使われている。.NET では通常、ソフトウェア コンポーネントのメカニズムとして使用され、発生したイベントについて別のコンポーネントに通知する。デリゲートとイベントは、JVM プラットフォーム上でも実装される。

デリゲート

デリゲートはメソッドへの参照を保持するクラスであり、インスタンス メソッドの場合は、そのメソッドを呼び出せるオブジェクトとなる。

デリゲート クラスのインスタンスが作成されると、保存されたインスタンス上の参照先メソッドが呼び出される場所で呼び出せるようになる。

1 つのデリゲート型に保持できるのは特定の署名のメソッドへの参照のみであるため、デリゲートの作成と呼び出しにおいて型の安全性が保たれる。

COBOL でデリゲートを定義する際には、DELEGATE-ID キーワードと、署名を指定する PROCEDURE DIVISION ヘッダーを使用する。例えば、文字列パラメーターを持ち、binary-long を返すデリゲートは、次のように宣言する。

delegate-id MyDelegate.
procedure division using by value s1 as string returning n1 as binary-long.
end delegate.
メソッド グループ

メソッド グループは、キーワード METHOD を前に置くメソッド呼び出し式であり、パラメーターは付かない。メソッド グループが指定された場合、それは複数のメソッドのうち、指定された名前を持つ、指定されたクラスのメソッドを示す。

メソッド グループと特定のデリゲート型の間では暗黙変換が行われるが、メソッド グループで指定されたメソッドが、そのデリゲート型と互換性のある署名を持つ場合に限る。

例えば、上記で宣言したデリゲートMyDelegate のインスタンスを作成し、適切なメソッドを示すようにするには、次のように記述する。

01 d type MyDelegate.
01 c type Class1.
...
set d to method c::m

class-id Class1.
method-id m.
procedure division using by value s1 as string returning n1 as binary-long.
end method.

method-id m.
procedure division using by value s1 as string s2 as string returning n1 as binary-long.
end method.

end class.

上記の例では、SET 文はメソッドm の最初のオーバーロードを自動的に選択する。これは、デリゲート型MyDelegateの署名と互換性のある署名を持っているためである。

メソッド グループはメソッドのパラメーターとして使用することもできるが、これはそのメソッドが互換性のあるデリゲート型の引数を持つ場合に限る。この場合にも、メソッド グループからデリゲート型への暗黙変換が行われ、そのデリゲートは対象メソッドにパラメーターとして渡される。

匿名メソッド

デリゲートがコードの一部分をポイントするよう設定できる。その際、コードを正式にメソッドにする必要はない。このようなコードは匿名メソッドと呼ばれ、キーワード DELEGATE および END-DELEGATE を使用して指定できる。

USING および RETURNING を使用して、パラメーターを指定して値を返す。USING および RETURNING は、DELEGATEに付加する。

次の例は、前述の例で作成したデリゲートMyDelegate に匿名メソッドを付加できることを示す。

01 d type MyDelegate.
set d to delegate using s1 as string
                                returning n1 as binary-long
                  set n1 to s1::Length
              end-delegate.
デリゲートの呼び出し

デリゲートを作成した後で削除するには、キーワード RUN を使用し、後に続けてデリゲート名およびかっこで囲んだパラメーターを記述する。例えば、上記で作成したデリゲートd を実行して結果を表示するには、次のように入力する。

display run d("Hello")

この文によって匿名メソッドを呼び出され、値 5 が返される。その後、この値が表示される。

デリゲートの作成と呼び出しの例
       delegate-id MyDelegate.
       procedure division using by value s1 as string returning n1 as binary-long.
       end delegate.

       class-id a.
       method-id main static.
       01 d type MyDelegate.
       01 c type Class1 value new Class1.


       set d to method c::m
       display run d("ABC")

       set d to delegate using s1 as string
                         returning n1 as binary-long
                    set n1 to s1::Length
                end-delegate
       display run d("XYZ")
       end method.
       end class.

       class-id Class1.
       method-id m.
       procedure division using by value s1 as string returning n1 as binary-long.
           set n1 to size of s1 + 3
       end method.
       method-id m.
       procedure division using by value s1 as string s2 as string returning n1 as binary-long.
       end method.
       end class.
デリゲートの結合

1 つのデリゲートで複数のオブジェクトやメソッドに対する参照を保持できる。このような場合、デリゲートが呼び出されると、各メソッドはデリゲートに追加された順序で呼び出される。

  • メソッド グループ、匿名メソッド、またはその他のデリゲートをデリゲートに追加するには、演算子「+」を使用する。
  • デリゲートからメソッドを削除するには、演算子「-」を使用する。
注:こうした式では、少なくとも右辺または左辺のいずれかをデリゲート型のインスタンスにする必要がある。

次に例を示す。

       class-id DelegateCombining.
       method-id main static.
       01 cd1 type D.
       01 cd2 type D.
       01 cd3 type D.
       01 c type C value new C.
           set cd1 to method type C::M1
           invoke cd1(-1)
           set cd2 to method type C::M2
           invoke cd2(-2)
           set cd3 to cd2 + method type C::M1
           invoke cd3(10)
           set cd3 to method type C::M1 + cd3
           invoke cd3(20)

           set cd3 to cd3 + method c::M3
           invoke cd3(30)

           set cd3 to cd3 - method type C::M1
           invoke cd3(40)
           set cd3 to cd3 - method c::M3
           invoke cd3(50)
           set cd3 to cd3 - method type C::M2
           invoke cd3(60)
           set cd3 to cd3 - cd2
           invoke cd3(60)
           set cd3 to cd3 - cd1
           try
               invoke cd3(70)
           catch
               display "null reference exception caught"
           end-try
           set cd3 to cd3 - cd1
 
           set cd1 to method type C::M1
           set cd2 to method type C::M2
           set cd3 to cd1 + cd2 + cd2 + cd1
           invoke cd3(80)
           set cd3 to cd3 - cd1
           invoke cd3(90)
           set cd3 to cd1 + cd2 + cd2 + cd1
           set cd3 to cd3 - (cd1 + cd2)
           invoke cd3(100)
           set cd3 to cd1 + cd2 + cd2 + cd1
           set cd3 to cd3 - (cd2 + cd2)
           invoke cd3(110)
           set cd3 to cd1 + cd2 + cd2 + cd1
           set cd3 to cd3 - (cd2 + cd1)
           invoke cd3(120)
           set cd3 to cd1 + cd2 + cd2 + cd1
           set cd3 to cd3 - (cd1 + cd1)
           invoke cd3(130)

       end method.
       end class.

       delegate-id D.
       procedure division using by value i as binary-long.
       end delegate.

       class-id C.
       method-id M1 static.
       procedure division using by value i as binary-long.
           display "C::M1 --> " i
       end method.
       method-id M2 static.
       procedure division using by value i as binary-long.
           display "C::M2 --> " i
       end method.
       method-id M3.
       procedure division using by value i as binary-long.
           display "C::M3 --> " i
       end method.
       end class.

イベント

イベントは、GUI 環境でキーが押されたなどの重要な事象の発生をクラスが通知するための手段である。

イベントを定義するには、キーワード EVENT をデリゲートのフィールドに追加する。次に例を示す。

       01 ChangeEvent type ChangeDelegate event public.

同じ型のデリゲート、または互換性のあるメソッド グループや匿名メソッドをイベントにアタッチできる。イベントを所有するクラスがバッキング デリゲートを呼び出す際に、これらは呼び出される。

イベントとそのバッキング デリゲートの関係は、プロパティとバッキング記憶域の関係に非常に似ている。

イベントへのメソッドまたはデリゲートのアタッチ

デリゲート、メソッド グループ、または匿名メソッドをイベントにアタッチするにはATTACH 文を使用する。

ATTACH {delegate-instance}    TO event-expression
                {method-group}
                {anonymous-method}

次に例を示す。

       01 names type myList.
       01 MyDelegate type ChangeDelegate.
       procedure division.
           set names to new myList
           attach method ListChanged to names::ChangeEvent
           set MyDelegate to method ListChanged
           attach MyDelegate to names::ChangeEvent
イベントからのメソッドまたはデリゲートのデタッチ

デリゲートまたはメソッド グループをイベントからデタッチするには、次のようにDETACH 文を使用する。

DETACH {delegate-instance}    FROM  event-expression
                {method-group}

次に例を示す。

           detach MyDelegate from names::ChangeEvent
           detach method ListChanged from names::ChangeEvent