連載

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

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

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

Page1 Page2 Page3 Page4

共有メソッドへの委譲

 上記の例を見て、掛け算も足し算も完全に独立した処理であり、共有メソッド(Sharedなメソッド)にしても何ら問題ないことに気付いた人もいるだろう。では、共有メソッドへの委譲は記述できるのだろうか? 以下はそのように修正してみたものである。

  1: Delegate Function SampleDelegate(ByVal x As Integer, ByVal y As Integer) As Integer
  2:
  3: Public Class SampleClass
  4:   Public Shared Function MethodMult(ByVal x As Integer, ByVal y As Integer) As Integer
  5:     Return x * y
  6:   End Function
  7:
  8:   Public Shared Function MethodPlus(ByVal x As Integer, ByVal y As Integer) As Integer
  9:     Return x + y
 10:   End Function
 11: End Class
 12:
 13: Public Class Form1
 14:   Inherits System.Windows.Forms.Form
 15:
 16: …Windows フォーム デザイナで生成されたコード…
 17:
 18:   Private Sub calc(ByVal x As Integer, ByVal y As Integer, ByVal calcMethod As SampleDelegate)
 19:     Dim result As Integer = calcMethod(x, y)
 20:     Trace.WriteLine(result)
 21:   End Sub
 22:
 23:   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 24:     Dim instance As New SampleClass()
 25:     calc(2, 3, AddressOf SampleClass.MethodMult)
 26:     calc(2, 3, AddressOf SampleClass.MethodPlus)
 27:   End Sub
 28: End Class
サンプル・プログラム1の委譲先となる2つのメソッドを共有メソッドにしたサンプル・プログラム4

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

 1: 6
 2: 5
サンプル・プログラム4の実行結果

 Sharedなメソッドを指定するために、インスタンス名の代わりにクラス名を使用することができる。25行目のSampleClass.MethodMultのようにメソッド名を記述すれば、そのままSharedなメソッドを利用可能である。それ以外には特別な記述はなく、デリゲートの宣言や呼び出し時に特別な配慮は必要ないことが分かると思う。

デリゲートはインスタンスを選ぶ

 これは非常に重要なことなので、よく頭に刻み込んでほしいところなのだが、共有メソッドを使う場合を除き、デリゲートはインスタンスとメソッドの情報を扱う。つまり、デリゲートが委譲する先は、ただ単に指定されたメソッドが呼ばれるだけでなく、呼び出し時にどのインスタンスかも明示される。以下は、複数インスタンスのメソッドを委譲先として使用したサンプル・プログラムである。

  1: Delegate Function SampleDelegate(ByVal x As Integer, ByVal y As Integer) As Integer
  2:
  3: Public Class SampleClass
  4:   Public result As Integer
  5:   Public Function SampleMethod(ByVal x As Integer, ByVal y As Integer) As Integer
  6:     result = x * y
  7:   End Function
  8: End Class
  9:
 10: Public Class Form1
 11:   Inherits System.Windows.Forms.Form
 12:
 13: …Windows フォーム デザイナで生成されたコード…
 14:
 15:   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 16:     Dim instance1 As New SampleClass()
 17:     Dim instance2 As New SampleClass()
 18:     Dim d1 As SampleDelegate = AddressOf instance1.SampleMethod
 19:     Dim d2 As SampleDelegate = AddressOf instance2.SampleMethod
 20:     d1(2, 3)
 21:     d2(4, 5)
 22:     Trace.WriteLine(instance1.result)
 23:     Trace.WriteLine(instance2.result)
 24:   End Sub
 25: End Class
2つの異なるインスタンスのデリゲートを呼び出すサンプル・プログラム5

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

 1: 6
 2: 20
サンプル・プログラム5の実行結果

 ここでは、同じSampleClassクラスのインスタンスを2つ作成している(16〜17行目)。この2つのインスタンスに対して別々にデリゲート・インスタンスを作成している(18〜19行目)。さてここからが、このサンプル・プログラム最大の注目点なのだが、20〜21行目のメソッド呼び出しには、どのSampleClassインスタンスを対象にするか、明示的には表現されていない。しかし、デリゲート・インスタンスは、どのSampleClassインスタンスを対象とするかを覚えているので、間違いなく、18〜19行目で指定されたSampleClassインスタンスのメソッドを呼び出す。

 このように、デリゲートはメソッドだけでなくインスタンスも識別することを、よく覚えておいていただきたい。特にC/C++の関数ポインタをご存じの方は注意が必要である。関数ポインタは関数を特定する機能しか持たず、インスタンスを特定する情報は持たないのである。

戻り値と引数が合えば委譲できる

 デリゲートは、対象となるメソッドにPrivateキーワードなどが付加されてアクセス権が与えられていない場合などを除き、戻り値と引数が合えば委譲できる。別クラスの異なる名前のメソッドであっても、戻り値と引数だけ合っていれば委譲できる。以下は、まったく無関係な別クラスの異なる名前のメソッドに委譲した例である。

  1: Delegate Function SampleDelegate(ByVal x As Integer, ByVal y As Integer) As Integer
  2:
  3: Public Class SampleClass1
  4:   Public result As Integer
  5:   Public Function MethodMult(ByVal x As Integer, ByVal y As Integer) As Integer
  6:     result = x * y
  7:   End Function
  8: End Class
  9:
 10: Public Class SampleClass2
 11:   Public result As Integer
 12:   Public Function MethodPlus(ByVal x As Integer, ByVal y As Integer) As Integer
 13:     result = x + y
 14:   End Function
 15: End Class
 16:
 17: Public Class Form1
 18:   Inherits System.Windows.Forms.Form
 19:
 20: …Windows フォーム デザイナで生成されたコード…
 21:
 22:   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 23:     Dim instance1 As New SampleClass1()
 24:     Dim instance2 As New SampleClass2()
 25:     Dim d1 As SampleDelegate = AddressOf instance1.MethodMult
 26:     Dim d2 As SampleDelegate = AddressOf instance2.MethodPlus
 27:     d1(2, 3)
 28:     d2(4, 5)
 29:     Trace.WriteLine(instance1.result)
 30:     Trace.WriteLine(instance2.result)
 31:   End Sub
 32: End Class
無関係なクラスの異なる名前のメソッドに委譲するサンプル・プログラム6

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

 1: 6
 2: 9
サンプル・プログラム6の実行結果

 このサンプル・プログラムはここまで説明した知識だけで読みとれると思う。このように、デリゲートは自由度の高い機能なのである。


 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 記事ランキング

本日 月間