連載

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

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

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

Page1 Page2 Page3 Page4

継承でも実現できるか?

 異なるクラスのメソッドを1つのメソッド呼び出しで扱うというのは、何もデリゲートだけが持つ機能ではない。クラスの継承や、インターフェイスの機能を使ってもこれは実現できる。以下は継承を使って実現してみた例である。これを、デリゲートを使った場合と比較して考えてみよう。

  1: Public MustInherit Class ClassBase
  2:   Public MustOverride Function Method(ByVal x As Integer, ByVal y As Integer) As Integer
  3: End Class
  4:
  5: Public Class ClassMult
  6:   Inherits ClassBase
  7:   Public Overrides Function Method(ByVal x As Integer, ByVal y As Integer) As Integer
  8:     Return x * y
  9:   End Function
 10: End Class
 11:
 12: Public Class ClassPlus
 13:   Inherits ClassBase
 14:   Public Overrides Function Method(ByVal x As Integer, ByVal y As Integer) As Integer
 15:     Return x + y
 16:   End Function
 17: End Class
 18:
 19: Public Class Form1
 20:   Inherits System.Windows.Forms.Form
 21:
 22: …Windows フォーム デザイナで生成されたコード…
 23:
 24:   Private Sub calc(ByVal x As Integer, ByVal y As Integer, ByRef instance As ClassBase)
 25:     Dim result As Integer = instance.Method(x, y)
 26:     Trace.WriteLine(result)
 27:   End Sub
 28:
 29:   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 30:     Dim instance1 As New ClassMult()
 31:     Dim instance2 As New ClassPlus()
 32:     calc(2, 3, instance1)
 33:     calc(2, 3, instance2)
 34:   End Sub
 35: End Class
継承を使用し、1つのメソッド呼び出しで異なるクラスのメソッドを呼び出すサンプル・プログラム7

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

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

 このサンプル・プログラムは、25行目のメソッド呼び出しによって、掛け算をしたり、足し算をしたりする。機能面では、これまで説明したサンプル・プログラムと似ているが、コーディングにはいくつもの違いが見られる。まず、継承を使う方法ではメソッド名を統一しておく必要がある。また、あらかじめ基底クラス(ClassBase)でMustOverrideなメソッド宣言をしておき、機能を実装する場合はOverridesキーワードを付けてメソッドを記述する必要がある。戻り値と引数が合っていれば使用できるデリゲートと比較すれば、制約は大きいといえる。さらに、25行目を見て分かるとおり、具体的に呼び出すインスタンスとメソッドが直接記述されており、代表者としての役割を果たしているとはいい難い。

 このようにデリゲートはデリゲートという1つの機能であって、継承やインターフェイスとは異なる特徴を持っている。これらは、適切に使い分けられるべきものなのである。

デリゲートをオブジェクトとして使う

 デリゲートのインスタンスも、当然ながら一種のインスタンスである。これらは、System.DelegateクラスやSystem.MulticastDelegateクラスを継承しており、これらのクラスのメソッドやプロパティを呼び出すことができる。以下はその機能を用いて、デリゲート・インスタンスが指し示しているメソッドとインスタンスの属するクラス名を出力するようにした例である。

  1: Delegate Sub SampleDelegate()
  2:
  3: Public Class Form1
  4:   Inherits System.Windows.Forms.Form
  5:
  6: …Windows フォーム デザイナで生成されたコード…
  7:
  8:   Private Sub method()
  9:     Trace.WriteLine("Hello!")
 10:   End Sub
 11:
 12:   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 13:     Dim sample As SampleDelegate = AddressOf method
 14:     Trace.WriteLine(sample.Method.Name)
 15:     Trace.WriteLine(sample.Target.GetType().FullName)
 16:   End Sub
 17: End Class
デリゲートのインスタンスが指し示しているメソッドと、インスタンスの属するクラス名を出力するサンプル・プログラム8

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

 1: method
 2: Sample007n.Form1
サンプル・プログラム8の実行結果

 14行目のsample.Method.Nameは、デリゲートが持つメソッドに関する情報を、Methodプロパティを通じて取り出し、さらにメソッドの名前を持つNameプロパティを読み出している。15行目のsample.Target.GetType().FullNameは、まず、デリゲート・インスタンスが対象とするインスタンスをTargetプロパティで取り出し、それに対してGetType().FullNameを適用することで、クラス名を取り出している。暗黙のうちに、このサンプル・プログラムのプロジェクト名である「Sample007n」と同じ名前の名前空間が仮定されるので、クラスのフルネームはSample007n.Form1となっている。

privateなメソッドへの委譲

 デリゲートを用いてアクセス権限のないメソッドへ委譲することはできないが、アクセス権限のないメソッドを呼び出せないわけではない。デリゲート・インスタンスを作成する時点で、呼び出すべきメソッドへのアクセス権限があればよいのであって、メソッド呼び出しそのものを行うときにはアクセス権限がなくてもよい。実際に、アクセス権限のないメソッド呼び出しが、デリゲートを経由することで可能になっている例を以下に示す。

  1: Public Delegate Sub SampleDelegate(ByVal message As String)
  2:
  3: Public Class SampleClass
  4:   Private Sub outputMessage(ByVal message As String)
  5:     Trace.WriteLine(message)
  6:   End Sub
  7:
  8:   Public Function GetDelegate() As SampleDelegate
  9:     Return AddressOf MyClass.outputMessage
 10:   End Function
 11: End Class
 12:
 13: Public Class Form1
 14:   Inherits System.Windows.Forms.Form
 15:
 16: …Windows フォーム デザイナで生成されたコード…
 17:
 18:   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 19:     Dim instance As New SampleClass()
 20:     Dim sample As SampleDelegate = instance.GetDelegate()
 21:     sample("Hello!")
 22:   End Sub
 23: End Class
アクセス権限のないメソッドをデリゲート経由で呼び出すサンプル・プログラム9

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

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

 もし、21行目に、4〜6行目のoutputMessageメソッドへの呼び出しを記述した場合、コンパイル・エラーになるのは当たり前である。しかし、このサンプル・プログラムは正常に動作する。そのポイントは、デリゲート・インスタンスを作成するとき(9行目)には、outputMessageメソッドへのアクセス権がある、という点にある。もし、9行目をForm1クラス内に移動させたら、このソースはコンパイルできなくなる。


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

本日 月間