デリゲートおよびイベント

デリゲートは、オブジェクト指向の手続きポインターに相当し、型の安全性を保つソリューションを提供します。デリゲートは EVENT キーワードと組み合わせて使用し、一般的には、GUI 環境でキーが押された場合など、発生したイベントについて他のソフトウェア コンポーネントに通知するためのメカニズムとして使用します。

コンテキスト:

プログラム構造 

delegate-specification

delegate-specification の構文 delegate-header procedure-division-header

delegate-header

delegate-header の構文 メソッドのシグネチャメソッドのシグネチャを使用すると、特定の要素のヘッダー内で、渡すパラメーターおよび戻り項目を指定できます。このシグネチャを使用する場合は、メソッド内の手続き部の見出しを省きます。 access-modifier attribute-clause

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 Groups

A method group is a method invocation expression preceded by the keyword METHOD, and without any parameters. When a method group is specified, it denotes one of the set of methods with the specified name in the specified class.

An implicit conversion exists between a method group and a specific delegate type, if one of the methods identified by the method group has a signature which is compatible with that delegate type.

For example, to create an instance of the delegate MyDelegate you declared above, that points to a suitable method:

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.

In the example above, the SET statement automatically selects the first overload of the method m as it has a signature which is compatible with that of the delegate type MyDelegate.

A method group can also be used as a parameter to a method, when that method has an argument of a compatible delegate type. Again, an implicit conversion from the method group to the delegate type will take place, and that delegate will be passed as the parameter to the target method.

Anonymous methods

You can set a delegate to point to a piece of code, without formally setting that code up as a specific method. Such a piece of code is called an Anonymous Method, and you use the keywords DELEGATE and END-DELEGATE to specify it.

You specify any parameters and return values with the words USING and RETURNING attached to the word DELEGATE.

The following shows how you can attach an anonymous method to the delegate MyDelegate you created in the previous examples:

01 d type MyDelegate.
set d to delegate using s1 as string
                                returning n1 as binary-long
                  set n1 to s1::Length
              end-delegate.
Invoking delegates

To invoke a delegate after it has been created, you use the keyword RUN followed by the delegate name, and any parameters enclosed in parentheses. For example, to run the delegate d created above and displaying the results, type:

display [run] d("Hello")

This statement causes the anonymous method to be invoked and return a value of 5. This value is then displayed. Note, run is an optional keyword.

Example of creating and invoking delegates
       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.
Combining delegates

A single delegate can hold references to more than one object/method pair. In such cases, at the time when the delegate is invoked, each one of the methods will be invoked in the order in which they were added to the delegate.

  • You use the operator '+' to add a method group, anonymous method or another delegate to a delegate.
  • You use the operator '-' to remove methods from a delegate.
注: At least one side of such an expression must be an instance of a delegate type.

For example:

       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.

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

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

Attaching a method or a delegate to an event

You use the ATTACH statement to attach a delegate, method group or an anonymous method to an event:

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

For example:

       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
To detach a method or a delegate from an event

To detach a delegate or method group from an event use the DETACH statement:

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

For example:

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