デリゲートのインスタンスは委譲先メソッドに関する情報を含むが、この情報はリストとして保持される。つまり、委譲先メソッドは複数指定することもできるというわけである。List 13-9は2つの委譲先メソッドを指定した例である。
1: using System;
2:
3: namespace Sample009
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: [STAThread]
20: static void Main(string[] args)
21: {
22: Class2 instance = new Class2();
23: Sample sample1 = new Sample( instance.method1 );
24: sample1();
25: Sample sample2 = new Sample( instance.method2 );
26: sample2();
27: Sample sample3 = sample1 + sample2;
28: sample3();
29: }
30: }
31: }
これを実行するとFig.13-9のようになる。
ここでポイントになるのは、27行目の+演算子である。デリゲート・インスタンスは、+演算子や+=演算子で足し合わせることができる。その結果、2つのデリゲート・インスタンスが持つ委譲先メソッドのリストが合成され、1つのリストにまとめられる。
このように複数の委譲先メソッドが合成されたデリゲート・インスタンスを、28行目のように呼び出すと、リストに属するすべてのメソッドが呼び出される。複数の処理をまとめて実行させるには便利な機能だが、戻り値を受け取りたい場合は適切ではない。一度にいくつものメソッドを呼び出せるが、受け取れる戻り値は最後に呼ばれたメソッドの戻り値、ただ1つだけである。
デリゲートに含まれる委譲先リストは、いつでも追加削除できる。追加には+や+=演算子を使い、削除には-=演算子を用いる。List 13-10はリストの追加と削除を行うサンプル・ソースである。
1: using System;
2:
3: namespace Sample010
4: {
5: delegate void Sample();
6: class Class2
7: {
8: private string name;
9: public Class2( string name )
10: {
11: this.name = name;
12: }
13: public void method()
14: {
15: Console.WriteLine(name);
16: }
17: }
18: class Class1
19: {
20: [STAThread]
21: static void Main(string[] args)
22: {
23: Sample samples = new Sample( new Class2("test1").method );
24: Sample sample2 = new Sample( new Class2("test2").method );
25: Sample sample3 = new Sample( new Class2("test3").method );
26: Sample sample4 = new Sample( new Class2("test4").method );
27: Console.WriteLine("call 1 method");
28: samples();
29: samples += sample2;
30: samples += sample3;
31: samples += sample4;
32: Console.WriteLine("call 4 methods");
33: samples();
34: samples -= sample2;
35: Console.WriteLine("call 3 methods");
36: samples();
37: }
38: }
39: }
これを実行するとFig.13-10のようになる。
28行目の段階では、samplesには1つしかメソッドが登録されていないので、それだけが呼ばれる。しかし、33行目の段階では、4つのメソッドが登録されいて、それらのすべてが呼び出される。しかし、34行目で1つの委譲先を取り除いているので、36行目の段階では、3つのメソッドが呼び出されている。
デリゲートで委譲するメソッドは戻り値と引数が一致していればよいと書いたが、デリゲート型同士は、戻り値と引数が一致していても、同じとは見なされない。List 13-11はコンパイルできない誤った例である。
1: using System;
2:
3: namespace Sample011
4: {
5: delegate void Sample1();
6: delegate void Sample2();
7: class Class1
8: {
9: public static void method()
10: {
11: Console.WriteLine("Hello!");
12: }
13: [STAThread]
14: static void Main(string[] args)
15: {
16: Sample1 samples = new Sample1( Class1.method );
17: Sample2 sample2 = new Sample2( Class1.method );
18: samples += sample2; // 演算子 '+=' を 'Sample011.Sample1' と 'Sample011.Sample2' 型のオペランドに適用することはできません。
19: samples();
20: }
21: }
22: }
18行目のように、異なるデリゲート型のデリゲート・インスタンスを1つのリストにまとめることはできない。例え、戻り値と引数が一致していても、である。
『新プログラミング環境 C#がわかる+使える』
本記事は、(株)技術評論社が発行する書籍『新プログラミング環境 C#がわかる+使える』から許可を得て一部分を転載したものです。
【本連載と書籍の関係について 】
この書籍は、本フォーラムで連載した「C#入門」を大幅に加筆修正し、発行されたものです。連載時はベータ版のVS.NETをベースとしていましたが、書籍ではVS.NET製品版を使ってプログラムの検証などが実施されています。技術評論社、および著者である川俣晶氏のご好意により、書籍の内容を本フォーラムの連載記事として掲載させていただけることになりました。
→技術評論社の解説ページ
ご注文はこちらから
Copyright© Digital Advantage Corp. All Rights Reserved.