![]() |
![]() |
delegate-id MessageHandler (str as string). end delegate. class-id DelegatesEvents. 01 MessageArrived event type MessageHandler static. method-id Main static. *> explicit delegate construction invoke new MessageHandler(MyHandler) *> implicit delegate construction declare handler as type MessageHandler = method MyHandler *> subscribe to an event attach method MyHandler to MessageArrived *> raise the event invoke MessageArrived("Test message") *> unsubscribe from the event detach method MyHandler from MessageArrived *> Throws a null reference exception as there are no subscribers invoke MessageArrived("Test message 2") *> Safely raising an #event declare handler2 as type MessageHandler = MessageArrived if handler2 not equals null invoke handler1("Safe message") end-if end method. method-id MyHandler static (str as string). display str end method. end class.
デリゲートはメソッドへの参照を保持するクラスであり、インスタンス メソッドの場合は、そのメソッドを呼び出せるオブジェクトとなります。
デリゲート クラスのインスタンスが作成されると、保存されたインスタンス上の参照先メソッドが呼び出される場所で呼び出せるようになります。
1 つのデリゲート型に保持できるのは特定のシグネチャのメソッドへの参照のみであるため、デリゲートの作成および呼び出しにおいて型の安全性が保たれます。
COBOL でデリゲートを定義する際には、DELEGATE-ID キーワードと、シグネチャを指定する手続き部の見出しを使用します。たとえば、文字列パラメーターを持ち、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 を使用して指定できます。
語 DELEGATE に語 USING および RETURNING を付加して、パラメーターの指定と値を返します。
次の例は、前述の例で作成したデリゲート 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