デリゲートには複数のメソッドを登録でき、1 回の呼び出しで全員に通知できます。このしくみをマルチキャストデリゲートと呼びます。
このページを読み終えると、以下のことができるようになります。
+= でデリゲートにメソッドを追加できる-= で登録したメソッドを解除できるGetInvocationList() で登録済みメソッドを個別に呼び出せる+= でメソッドを追加する書式:デリゲートへのメソッド追加
1
デリゲート変数 += メソッド名;
| 要素 | 説明 |
|---|---|
デリゲート変数 |
複数のメソッドを管理するデリゲート変数 |
+= |
デリゲートに新しいメソッドを追加する演算子 |
メソッド名 |
追加するメソッド(シグネチャが一致すること) |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
public delegate void Notify();
public class Program
{
public static void Main()
{
Notify? notify = null;
notify += SayHello;
notify += SayGoodbye;
notify?.Invoke();
}
private static void SayHello()
{
Console.WriteLine("こんにちは!");
}
private static void SayGoodbye()
{
Console.WriteLine("さようなら!");
}
}
1
2
こんにちは!
さようなら!
notify?.Invoke() を 1 回呼び出すだけで、登録した順に SayHello → SayGoodbye が実行されます。
-= でメソッドを解除する書式:デリゲートからのメソッド解除
1
デリゲート変数 -= メソッド名;
| 要素 | 説明 |
|---|---|
-= |
登録されているメソッドをデリゲートから取り除く演算子 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System;
public delegate void Notify();
public class Program
{
public static void Main()
{
Notify? notify = null;
notify += SayHello;
notify += SayGoodbye;
notify -= SayHello; // SayHello だけ解除
notify?.Invoke();
}
private static void SayHello()
{
Console.WriteLine("こんにちは!");
}
private static void SayGoodbye()
{
Console.WriteLine("さようなら!");
}
}
1
さようなら!
SayHello が解除されたため、SayGoodbye だけが呼び出されます。登録されていないメソッドを -= で解除しようとしても、エラーにはなりません。
複数のメソッドが登録されたデリゲートに戻り値がある場合、最後に登録したメソッドの戻り値だけが返ります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
public delegate int Calculate(int x);
public class Program
{
public static void Main()
{
Calculate calc = Double;
calc += Triple;
int result = calc(5);
Console.WriteLine(result); // Triple(5) = 15 だけが返る
}
private static int Double(int x) => x * 2; // 10 が返るが捨てられる
private static int Triple(int x) => x * 3; // 15 が返る
}
1
15
Double の戻り値 10 は無視されます。複数の戻り値を個別に使いたい場合は、次のセクションで説明する GetInvocationList() を使います。
GetInvocationList() で個別に呼び出すGetInvocationList() は、デリゲートに登録されているメソッド一覧を配列で返します。これを使うと、各メソッドの戻り値を個別に受け取れます。
Delegate.GetInvocationList — デリゲートに登録されている全メソッドを Delegate[] として返します。
書式:Delegate.GetInvocationList メソッド
1
Delegate[] GetInvocationList();
| パラメータ | 型 | 説明 |
|---|---|---|
| (なし) | — | パラメータはありません |
| 戻り値 | Delegate[] |
登録されているメソッドを順番に並べた配列 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
public delegate int Calculate(int x);
public class Program
{
public static void Main()
{
Calculate calc = Double;
calc += Triple;
foreach (Calculate c in calc.GetInvocationList())
{
int result = c(5);
Console.WriteLine(result);
}
}
private static int Double(int x) => x * 2;
private static int Triple(int x) => x * 3;
}
1
2
10
15
各メソッドを個別に呼び出しているため、Double の結果 10 と Triple の結果 15 をそれぞれ取得できます。
1
2
3
4
5
6
7
// ❌ NG: null のデリゲートに += で追加後、?.Invoke() を使わずに呼び出す
Notify? notify = null;
notify += SayHello;
notify(); // コンパイルエラー(nullable なので直接呼び出し不可)
// ✅ OK: ?.Invoke() を使う
notify?.Invoke();
💡 ポイント:
nullだったデリゲートに+=でメソッドを追加すると、内部的に新しいデリゲートインスタンスが生成されます。変数はnullではなくなりますが、?.Invoke()を使う習慣をつけると安全です。
+= でデリゲートに複数のメソッドを追加でき、呼び出しは登録順に実行される-= で登録済みのメソッドを解除できるGetInvocationList() を使うと各メソッドの戻り値を個別に受け取れる以下の問いに答えられるか確認しましょう。
+= で 3 つのメソッドを追加して呼び出すと、どのような順で実行されますか?次のコードの出力結果は何になりますか?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
public delegate void Log(string msg);
public class Program
{
public static void Main()
{
Log? log = PrintA;
log += PrintB;
log -= PrintA;
log?.Invoke("test");
}
private static void PrintA(string msg) => Console.WriteLine($"A:{msg}");
private static void PrintB(string msg) => Console.WriteLine($"B:{msg}");
}
int を持つデリゲートに複数のメソッドを登録し、全メソッドの戻り値の合計を求めるにはどう書きますか?+= で追加した順)に実行されます。PrintA が -= で解除されているため、出力は次のとおりです。
1
B:test
GetInvocationList() で個別に呼び出して合計します。
1
2
3
4
5
6
int total = 0;
foreach (Calculate c in calc.GetInvocationList())
{
total += c(5);
}
Console.WriteLine(total);
イベント では、event キーワードによってデリゲートをより安全に扱う方法と、発行者/購読者パターンを学びます。