デリゲート
最終更新:
atachi
デリゲート
関数ポインタの配列のような扱いをするものである。
デリゲートは呼び出しリストを内部で持っており、宣言時のシグネチャと同じ関数を登録していく。(ただし、シグネチャは完全に一致しなくても良い)
delegate void SomeMethod(int a); // int型引数と戻り値の型がvoidのデリゲート
デリゲートのシグネチャはポリモーフィズムを考慮している。
次のように、object型を引数に持つ場合、object型を派生したクラスならシグネチャは一致する為、デリゲートへ登録できる。
delegate void SomeMethod(object a); // object型引数と戻り値の型がvoidのデリゲート
SomeMethod m = a;
m += b;
static void A(string a);
static void B(int b);
デリゲートへの登録・削除
デリゲートが呼び出す関数をエンティティと呼ぶ。
2つ以上のエンティティを呼び出しリストに登録したデリゲートをマルチキャストデリゲートと呼ぶ。
delegate void SomeMethod(int a);
class MainTest {
static void Main() {
SomeMethod d = new SomeMethod(A); // 初期化時にエンティティを追加
// C#2からは、次のようにも記述できる
// SomeMethod d = A;
d(10); // デリゲートの呼び出し
Message myObj = new Message("インスタンスです");
d += new SomeMethod(myObj.SomeMethod); // インスタンスメソッドもデリゲートに登録可能
d(10); // デリゲートの呼び出し
}
static void A(int a) {
Console.Write("A({0})",a);
}
}
class Message {
String message;
public Message(String message) {
this.message = message;
}
public void SomeMethod(int a){
Console.Write("{0} - {1}",a,this.message);
}
デリゲートへ登録したエンティティを呼び出しリストから削除するには「-=」を使用します。
delegate void SomeMethod(int a);
class MainTest {
static void Main() {
SomeMethod d = new SomeMethod(A); // 初期化時にエンティティを追加
// C#2からは、次のようにも記述できる
// SomeMethod d = A;
d = new SomeMethod(B);
d(10); // デリゲートの呼び出し(A()とB()が呼び出される)
d -= A;
d(10); // デリゲートの呼び出し(B()だけが呼び出される)
}
static void A(int a) {
Console.Write("A({0})",a);
}
static void B(int a) {
Console.Write("B({0})",a);
}
}
同じデリゲートインスタンスならば、デリゲートとデリゲートを組み合わせる事ができる。
delegate void SomeMethod(int a);
class MainTest {
static void Main() {
SomeMethod d1 = A;
SomeMethod d2 = B;
SomeMethod all = d1 + d2; // デリゲートの足し算
all(10); // デリゲートの呼び出し(A()とB()が呼び出される)
}
static void A(int a) {
Console.Write("A({0})",a);
}
static void B(int a) {
Console.Write("B({0})",a);
}
}
同期実行・非同期実行
デリゲートの実行は「同期実行」で行われ、その順番は呼び出しリストに登録された順となります。
非同期でデリゲートを呼び出すと、デリゲートの呼び出し元はデリゲートの処理が終了するまで待つ必要が無くなります。
ただし、マルチキャストデリゲートは非同期でデリゲートを実行することはできません。
デリゲートを非同期で呼び出すには、デリゲートクラスのメンバ関数であるBeginInvoke()を使用してデリゲートを呼び出します。
delegate void SomeMethod(int a);
class MainTest {
static void Main() {
SomeMethod d1 = A;
// 非同期でデリゲートを実行する
IAsyncResult ar = d1.BeginInvoke(1, null, null);
d1.EndInvoker(ar); // デリゲートの終了までウエイト
}
static void A(int a) {
Console.Write("A({0})",a);
}
}