デリゲート(delegate: 代表、委譲、委託)とは、メソッドを参照するための型です。
機能は、「ある処理を他のメソッドに丸投げするためのもの」です。
C/C++言語の勉強をしたことがある人には、 「デリゲートとは関数ポインターや関数オブジェクトを拡張したもの」 と言った方が分かりやすいかもしれません。
ですが、C言語の関数ポインターと違うのは、 インスタンスメソッドを参照したり、 複数のメソッドを同時に参照する事が出来ます。
デリゲートの基本
デリゲートを使用するためにはまず、デリゲート型を定義します。
delegate 戻り値の型 デリゲート型名(引数リスト);
これによりデリゲートも1つの型として扱われます。
また、デリゲート型は自動的に System.Delegate クラスの派生クラスになります。
デリゲート型の変数には、 デリゲートの定義時に指定した物と同じ戻り値と引数リストを持つメソッドを代入する事が出来ます。
単純な例
デリゲートで実行する処理を持つクラスを用意します。
public class TestClass1 { private string _name; // 当オブジェクトの名前 // 当オブジェクトの名前を取得するためのプロパティ public string Name { get { return _name; } } public TestClass1(string name) { // コンストラクタ this._name = name; } public void DispName() { // 名前プロパティをコンソールに表示する Console.WriteLine(this.Name); } }
デリゲートを宣言して、デリゲートによりコンソールに表示するだけのプログラムです。
static void Main(string[] args) { // オブジェクトを生成 TestClass1 obj = new TestClass1("hoge"); // デリゲートを生成する DisplayString func = new delegateTest1.DisplayString(obj.DispName); // デリゲートの処理を実行 func(); }
実行するとコンソールウィンドウに”hoge”という文字列が表示されます。
マルチキャストデリゲート
デリゲートにはメソッドを参照し、 間接的なメソッド呼び出しを行う機能があり、+= 演算子を用いることで、複数のメソッドを代入する事が出来ます。
複数のメソッドを代入した状態で、デリゲート呼び出しを行うと、代入した全てのメソッドが呼び出されます。
先ほどのクラスと似たクラスを用意して、テストプログラムを作ってみます。
追加するクラス(TestClass2)
public class TestClass2 { private string _message; // メッセージ文字列 // メッセージ文字列を取得するためのプロパティ public string Message { get { return _message; } } public TestClass2(string message) { // コンストラクタ this._message = message; } public void DispMessage() { // メッセージプロパティをメッセージボックスで表示する System.Windows.Forms.MessageBox.Show(this.Message, "TestClass2", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information); } }
上記のクラスを追加して、先ほどのプログラムを変更してみます。
static void Test2(string[] args) { TestClass1 obj = new TestClass1("hoge"); TestClass2 msgobj = new TestClass2("メッセージ"); // デリゲートを生成する DisplayString func = null; func += new delegateTest1.DisplayString(obj.DispName); func += new delegateTest1.DisplayString(msgobj.DispMessage); // デリゲートの処理を実行 func(); }
デリゲート変数’func’に2つのメソッドを登録しましたが、処理呼び出しは1か所しかありません。
ですが、このプログラムを実行すると、コンソールに”hoge”という文字列が表示され、メッセージボックスが表示され、そこに「メッセージ」というメッセージが表示されます。
これは、’func’というデリゲート変数にメソッドが2つ登録されているので、デリゲートを1度呼び出しただけで登録された2つのメソッドが実行されます。
非同期呼び出し
デリゲート呼び出しは非同期に行うことも出来ます。 通常、メソッドを呼び出すとメソッド内の処理が完了するまで呼び出し元には戻ってきません。 このような動作を「同期呼び出し」と呼びます。
これに対して「非同期呼び出し」とは、 メソッドを呼び出した瞬間に呼び出し元に処理が戻ってくるような呼び出しのことです。
このデリゲートの「非同期呼び出し」を行うときは、マルチキャストデリゲートは使用できませんのでご注意ください。
引き続き、さきほどのクラスを使ってプログラムを変えて作ります。
static void Main(string[] args) { TestClass2 msgobj = new TestClass2("メッセージ"); // デリゲートを生成する DisplayString func = null; func = new delegateTest1.DisplayString(msgobj.DispMessage); // デリゲートの処理を非同期で実行 IAsyncResult ar = func.BeginInvoke(null, null); Console.WriteLine("ここは非同期で即座に実行されます"); func.EndInvoke(ar); // <-- EndInvoke()によりここでデリゲート処理が終わるまで待ちます System.Windows.Forms.MessageBox.Show("こちらはデリゲートが終わったら実行されます", "てすと"); }
このプログラムを実行すると、
デリゲートによりメッセージボックスが表示され、そこに「メッセージ」というメッセージが表示された状態で、コンソールウィンドウに”ここは非同期で即座に実行されます”という文字列が表示されます。
「メッセージ」というメッセージボックスを閉じると、「こちらはデリゲートが終わったら実行されます」というメッセージボックスが表示されます(こちらはデリゲートの処理である最初のメッセージボックスが閉じてデリゲート処理が終了するまで実行されません)。