連載

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

Chapter 11 デリゲート

株式会社ピーデー 川俣 晶
2004/07/22
Page1 Page2 Page3 Page4


 本記事は、(株)技術評論社が発行する書籍『VB6プログラマーのための入門 Visual Basic .NET 独習講座』の一部分を許可を得て転載したものです。同書籍に関する詳しい情報については、本記事の最後に掲載しています。

継承でも実現できるか?

 異なるクラスのメソッドを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つのメソッド呼び出しで異なるクラスのメソッドを呼び出すプログラム

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

1: 6
2: 5
リスト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」となっている。

Privateキーワードの付いたメソッドへの委譲

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

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

1: Hello!
リスト11-16 リスト11-15の実行結果

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


 INDEX
  [連載] 改訂版 プロフェッショナルVB.NETプログラミング
  Chapter 11 デリゲート
    1.デリゲートとは何か/2つの異なるメソッドに委譲する
    2.共有メソッドへの委譲/デリゲートはインスタンスを選ぶ/戻り値と引数が合えば委譲できる
  3.継承でも実現できるか?/デリゲートをオブジェクトとして使う/Privateキーワードの付いたメソッドへの委譲
    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メールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH