delegateをオブジェクトとして使う
delegateのインスタンスも、当然ながら一種のインスタンスである。これらは、System.DelegateクラスやSystem.MulticastDelegateクラスを継承しており、これらのクラスのメソッドやプロパティを呼び出すことができる。以下はその機能を用いて、delegateインスタンスが指し示しているメソッドとインスタンスの属するクラス名を出力するようにした例である。
1: using System;
2:
3: namespace ConsoleApplication26
4: {
5: delegate void Sample();
6: class Class1
7: {
8: public void method()
9: {
10: Console.WriteLine( "Hello!" );
11: }
12: static void Main(string[] args)
13: {
14: Class1 instance = new Class1();
15: Sample sample = new Sample( instance.method );
16: Console.WriteLine( sample.Method.Name );
17: Console.WriteLine( sample.Target.GetType().FullName );
18: }
19: }
20: } |
|
delegateのメソッド名とクラス名を表示するサンプル・プログラム7 |
delegateのインスタンスでは、System.Delegateクラスにあるメソッドやプロパティを利用することができる。 |
これを実行すると以下のようになる。
|
サンプル・プログラム7の実行結果 |
1行目は定義したメソッドの名前、2行目はそのメソッドを含むクラスのフルネームである。
|
16行目のsample.Method.Nameは、delegateが持つメソッドに関する情報をMethodプロパティを通じて取り出し、さらにメソッドの名前を持つNameプロパティを読み出している。17行目のsample.Target.GetType().FullNameは、まず、delegateインスタンスが対象とするインスタンスをTargetプロパティで取り出し、それに対してGetType().FullNameを適用することで、クラス名を取り出している。
privateなメソッドへの委譲
delegateを用いてアクセス権限のないメソッドへ委譲することはできないが、アクセス権限のないメソッドを呼び出せないわけではない。delegateインスタンスを作成する時点で、呼び出すべきメソッドへのアクセス権限があればよいのであって、メソッド呼び出しそのものを行うときにはアクセス権限がなくてもよい。実際に、アクセス権限のないメソッド呼び出しが、delegateを経由することで可能になっている例を以下に示す。
1: using System;
2:
3: namespace ConsoleApplication27
4: {
5: delegate void Sample( string message );
6: class Class2
7: {
8: private void outputMessage( string message )
9: {
10: Console.WriteLine( message );
11: }
12: public Sample getDelegate()
13: {
14: return new Sample( this.outputMessage );
15: }
16: }
17: class Class1
18: {
19: static void Main(string[] args)
20: {
21: Class2 instance = new Class2();
22: Sample sample = instance.getDelegate();
23: sample( "Hello!" );
24: }
25: }
26: } |
|
delegate経由でprivateなメソッドを呼び出すサンプル・プログラム8 |
privateなメソッドは別のクラスのメソッドから呼び出すことはできない。privateなメソッドと同じクラスでdelegateのインスタンスを作成している点がポイントである。 |
これを実行すると以下のようになる。
|
サンプル・プログラム8の実行結果 |
delegateのインスタンスを生成できれば、その移譲先のメソッドがprivateでも呼び出すことができる。
|
もし、23行目に、8〜11行目のoutputMessageメソッドへの呼び出しを記述したら、コンパイル・エラーになるのは当たり前である。しかし、このサンプル・ソースは正常に動作する。そのポイントは、delegateインスタンスを作成するとき(14行目)には、outputMessageメソッドへのアクセス権がある、という点にある。もし、14行目をClass1クラス内に移動させたら、このソースはコンパイルできなくなる。
移譲先の合成
delegateのインスタンスは移譲先メソッドに関する情報を含むが、この情報はリストとして保持される。つまり、移譲先メソッドは複数指定することもできるというわけである。以下は2つの移譲先メソッドを指定した例である。
1: using System;
2:
3: namespace ConsoleApplication28
4: {
5: delegate void Sample();
6: class Class2
7: {
8: public void method1()
9: {
10: Console.WriteLine("method1 called");
11: }
12: public void method2()
13: {
14: Console.WriteLine("method2 called");
15: }
16: }
17: class Class1
18: {
19: static void Main(string[] args)
20: {
21: Class2 instance = new Class2();
22: Sample sample1 = new Sample( instance.method1 );
23: sample1();
24: Sample sample2 = new Sample( instance.method2 );
25: sample2();
26: Sample sample3 = sample1 + sample2;
27: sample3();
28: }
29: }
30: } |
|
2つの移譲先メソッドを指定したサンプル・プログラム9 |
移譲先メソッドの情報はリストとして保持されており、26行目のように「+演算子」によって合成することができる。 |
これを実行すると以下のようになる。
|
サンプル・プログラム9の実行結果 |
下2行は、合成されたdelegate呼び出しで、2つのメソッドが順に呼び出されたことを示している。
|
ここでポイントになるのは、26行目の「+演算子」である。delegateインスタンスは、「+演算子」や「+=演算子」で足し合わせることができる。その結果、2つのdelegateインスタンスが持つ移譲先メソッドのリストが合成され、1つのリストにまとめられる。
このように複数の移譲先メソッドが合成されたdelegateインスタンスを、27行目のように呼び出すと、リストに属するすべてのメソッドが呼び出される。複数の処理をまとめて実行させるには便利な機能だが、戻り値を受け取りたい場合は適切ではない。一度にいくつものメソッドを呼び出せるが、受け取れる戻り値は最後に呼ばれたメソッドの戻り値ただ1つだけである。
Insider.NET 記事ランキング
本日
月間