|
|
連載
改訂版
プロフェッショナルVB.NETプログラミング
Chapter 11 デリゲート
株式会社ピーデー
川俣 晶
2004/07/22 |
|
|
異なるクラスのメソッドを1つのメソッド呼び出しで扱うというのは、何もデリゲートだけが持つ機能ではない。クラスの継承やインターフェイスの機能を使ってもこれは実現できる。リスト11-11は継承を使って実現してみた例である。これを、デリゲートを使った場合と比較して考えてみよう。
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
|
|
リスト11-11 継承を使用し、1つのメソッド呼び出しで異なるクラスのメソッドを呼び出すプログラム
|
これを実行すると以下のようになる。
|
リスト11-12 リスト11-11の実行結果
|
このサンプル・プログラムは、25行目のメソッド呼び出しによって、掛け算をしたり、足し算をしたりする。機能面では、本章のこれまでのサンプル・プログラムと似ているが、コーディングにはいくつもの違いが見られる。まず、継承を使う方法ではメソッド名を統一しておく必要がある。また、あらかじめスーパークラス(ClassBase)で、MustOverrideキーワードの付いたメソッド宣言をしておき、機能を実装する場合はOverridesキーワードを付けてメソッドを記述する必要がある。戻り値と引数が合っていれば使用できるデリゲートと比較すると、制約は大きいといえる。さらに、25行目を見て分かるとおり、具体的に呼び出すインスタンスとメソッドが直接記述されており、代表者としての役割を果たしているとはいいがたい。
このように、デリゲートはデリゲートという1つの機能であって、継承やインターフェイスとは異なる特徴を持っている。これらは、適切に使い分けられるべきものなのである。
デリゲートのインスタンスも、当然ながら一種のインスタンスである。これらは、System.DelegateクラスやSystem.MulticastDelegateクラスを継承しており、これらのクラスのメソッドやプロパティを呼び出すことができる。リスト11-13は、その機能を用いて、デリゲート・インスタンスが指し示しているメソッドと、インスタンスの属するクラス名を出力するようにした例である。
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
|
|
リスト11-13 デリゲートのインスタンスが指し示しているメソッドと、インスタンスの属するクラス名を出力するプログラム
|
これを実行すると以下のようになる。
1: method
2: Sample007n.Form1
|
|
リスト11-14 リスト11-13の実行結果
|
14行目のsample.Method.Nameは、デリゲートが持つメソッドに関する情報をMethodプロパティを通じて取り出し、さらにメソッドの名前を持つNameプロパティを読み出している。15行目のsample.Target.GetType().FullNameは、まず、デリゲート・インスタンスが対象とするインスタンスをTargetプロパティで取り出し、それに対してGetType().FullNameを適用することで、クラス名を取り出している。暗黙のうちに、このサンプル・プログラムのプロジェクト名である「Sample007n」と同じ名前の名前空間が仮定されるので、クラスのフルネームは「Sample007n.Form1」となっている。
デリゲートを用いてアクセス権限のないメソッドへ委譲することはできないが、アクセス権限のないメソッドを呼び出せないというわけではない。デリゲート・インスタンスを作成する時点で、呼び出すべきメソッドへのアクセス権限があればよいのであって、メソッド呼び出しそのものを行うときにはアクセス権限がなくてもよい。実際に、アクセス権限のないメソッド呼び出しが、デリゲートを経由することで可能になっている例をリスト11-15に示す。
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
|
|
リスト11-15 アクセス権限のないメソッドをデリゲート経由で呼び出すプログラム
|
これを実行すると以下のようになる。
|
リスト11-16 リスト11-15の実行結果
|
ここで、21行目に、4〜6行目のoutputMessageメソッドへの呼び出しを記述した場合、コンパイル・エラーになるのは当たり前である。しかし、このサンプル・プログラムは正常に動作する。そのポイントは、デリゲート・インスタンスを作成するとき(9行目)には、outputMessageメソッドへのアクセス権がある、という点にある。もし、9行目をForm1クラス内に移動させたとすると、このソースはコンパイルできなくなる。
業務アプリInsider 記事ランキング
本日
月間