連載

プロフェッショナルVB.NETプログラミング

第23回 処理を委譲するデリゲート

(株)ピーデー
川俣 晶
2002/11/02

Page1 Page2 Page3 Page4

委譲先の合成

 デリゲートのインスタンスは委譲先メソッドに関する情報を含むが、この情報は「リスト」として保持される。つまり、委譲先メソッドは複数指定することもできるというわけである。以下は2つの委譲先メソッドを指定した例である。

  1: Delegate Sub SampleDelegate()
  2:
  3: Public Class Class2
  4:   Public Sub Method1()
  5:     Trace.WriteLine("Method1 called")
  6:   End Sub
  7:   Public Sub Method2()
  8:     Trace.WriteLine("Method2 called")
  9:   End Sub
 10: End Class
 11:
 12: Public Class Form1
 13:   Inherits System.Windows.Forms.Form
 14:
 15: …Windows フォーム デザイナで生成されたコード…
 16:
 17:   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 18:     Dim instance As New class2()
 19:     Dim sample1 As SampleDelegate = AddressOf instance.Method1
 20:     sample1()
 21:     Dim sample2 As SampleDelegate = AddressOf instance.Method2
 22:     sample2()
 23:     Dim sample3 As SampleDelegate = System.Delegate.Combine(sample1, sample2)
 24:     sample3()
 25:   End Sub
 26: End Class
1つのデリゲートに2つのメソッドを指定したサンプル・プログラム10

 これを実行すると以下のようになる。

 1: Method1 called
 2: Method2 called
 3: Method1 called
 4: Method2 called
サンプル・プログラム10の実行結果

 ここでポイントになるのは、23行目のSystem.Delegate.Combineメソッドである。これはSystem.Delegateクラスの共有メソッドである。ここでSystemというキーワードが必要になるのは、ただDelegateとだけ記述すると、VB.NETのDelegateキーワードとして扱われてしまうためである。このメソッドを使えば、複数のデリゲートを合成した新しいデリゲートを作成できる。つまり、2つのデリゲート・インスタンスが持つ委譲先メソッドのリストが合成され、1つのリストにまとめられる。

 このように複数の委譲先メソッドが合成されたデリゲート・インスタンスを、24行目のように呼び出すと、リストに属するすべてのメソッドが呼び出される。複数の処理をまとめて実行させるには便利な機能だが、戻り値を受け取りたい場合は適切ではない。一度にいくつものメソッドを呼び出せるが、受け取れる戻り値は最後に呼ばれたメソッドの戻り値ただ1つだけである。

委譲先リストの変更

 デリゲートに含まれる委譲先リストはいつでも追加/削除できる。追加にSystem.Delegate.Combineメソッドを用いることはすでに述べたが、削除する場合はSystem.Delegate.Removeメソッドを用いる。以下はリストの追加と削除を行うサンプル・プログラムである。

  1: Delegate Sub SampleDelegate()
  2:
  3: Public Class SampleClass
  4:   Private name As String
  5:   Public Sub New(ByVal name As String)
  6:     MyBase.New()
  7:     Me.name = name
  8:   End Sub
  9:
 10:   Public Sub Method()
 11:     Trace.WriteLine(name)
 12:   End Sub
 13: End Class
 14:
 15: Public Class Form1
 16:   Inherits System.Windows.Forms.Form
 17:
 18: …Windows フォーム デザイナで生成されたコード…
 19:
 20:   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 21:     Dim samples As SampleDelegate
 22:     samples = AddressOf New SampleClass("sample1").Method
 23:     Dim sample2 As SampleDelegate = AddressOf New SampleClass("sample2").Method
 24:     Dim sample3 As SampleDelegate = AddressOf New SampleClass("sample3").Method
 25:     Dim sample4 As SampleDelegate = AddressOf New SampleClass("sample4").Method
 26:     Trace.WriteLine("call 1 method")
 27:     samples()
 28:     samples = System.Delegate.Combine(samples, sample2)
 29:     samples = System.Delegate.Combine(samples, sample3)
 30:     samples = System.Delegate.Combine(samples, sample4)
 31:     Trace.WriteLine("call 4 method")
 32:     samples()
 33:     samples = System.Delegate.Remove(samples, sample2)
 34:     Trace.WriteLine("call 3 method")
 35:     samples()
 36:   End Sub
 37: End Class
委譲先リストの追加と削除を行うサンプル・プログラム11

 これを実行すると以下のようになる。

  1: call 1 method
  2: sample1
  3: call 4 method
  4: sample1
  5: sample2
  6: sample3
  7: sample4
  8: call 3 method
  9: sample1
 10: sample3
 11: sample4
サンプル・プログラム11の実行結果

 27行目の段階では、samplesには1つしかメソッドが登録されていないので、それだけが呼ばれる。しかし、32行目の段階では、4つのメソッドが登録されていて、それらのすべてが呼び出される。しかし、33行目で1つの委譲先を取り除いているので、35行目の段階では3つのメソッドが呼び出されている。System.Delegate.Removeメソッドは、第1引数のリストから、第2引数のリストのメソッドを取り除く。

デリゲート型の同一性

 デリゲートで委譲するメソッドは戻り値と引数が一致していればよいと書いたが、デリゲート型同士は、戻り値と引数が一致していても同じとは見なされない。以下のサンプル・プログラムは実行するとランタイム・エラーで停止する。

  1: Delegate Sub SampleDelegate1()
  2: Delegate Sub SampleDelegate2()
  3:
  4: Public Class Form1
  5:   Inherits System.Windows.Forms.Form
  6:
  7: …Windows フォーム デザイナで生成されたコード…
  8:
  9:   Public Shared Sub Method()
 10:     Trace.WriteLine("Hello!")
 11:   End Sub
 12:
 13:   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 14:     Dim samples As SampleDelegate1 = AddressOf Method
 15:     Dim sample2 As SampleDelegate2 = AddressOf Method
 16:     samples = System.Delegate.Combine(samples, sample2)
 17:     samples()
 18:   End Sub
 19: End Class
異なるデリゲート型を委譲先リストに格納して呼び出すサンプル・プログラム12(実行時にエラーとなる)

 16行目のように、異なるデリゲート型のデリゲート・インスタンスを1つのリストにまとめることはできない。たとえ戻り値と引数が一致していても、である。実行すると「デリゲートは同じ型でなければなりません」というランタイムのエラー・メッセージが出力される。

次回予告

 次回はイベントとウィンドウ・アプリケーションの仕組みに関する解説を予定している。End of Article


 INDEX
  連載 プロフェッショナルVB.NETプログラミング
  第23回 処理を委譲するデリゲート
    1.デリゲートとは何か
    2.共有メソッドへの委譲
    3.継承でも実現できるか?
  4.委譲先の合成
 
「プロフェッショナルVB.NETプログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間