デリゲートとイベント
CoddyのC#ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 43/70。
delegateは、メソッドへの参照を表す型です。データの代わりにメソッドを保持する変数だと考えてください。これにより、メソッドを引数として渡したり、コレクションに格納したり、動的に呼び出したりできます。
参照できるメソッドのシグネチャを指定して delegate を Declare します。
public delegate void Notify(string message);
public class Publisher
{
public void SendAlert(string msg) => Console.WriteLine("Alert: " + msg);
}
// 使用例
Notify notifier = new Publisher().SendAlert;
notifier("System started"); // Alert: System startedイベントはデリゲートを基盤として、パブリッシュ・サブスクライブパターンを実装します。class はイベントを raise し、他のclass は通知を受け取るために Subscribe できます。event キーワードはデリゲートの使用方法を制限します。サブスクライバーは handler を追加または削除することだけができ、イベントを直接 Invoke することはできません。
public class Button
{
public event Action Clicked;
public void Click()
{
Clicked?.Invoke(); // すべての購読者に通知する
}
}
// 購読
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click(); // ボタンがクリックされました!+= 演算子は handler を Subscribe し、-= は Subscribe を解除します。?.Invoke() pattern は、subscribers が存在する場合にのみ event を safely 呼び出します。event は GUI アプリケーション、ゲームエンジン、およびオブジェクトが密結合せずに変更へ反応する必要があるあらゆるシステムの基本です。
チャレンジ
簡単温度が変化するたびに delegate とイベントを使用して subscriber に通知する、温度監視システムを構築しましょう。これは、イベントによって非常に優雅に実現できる publish-subscribe パターンの典型的な例です。
コードを2つのファイルに分けて整理します。
TemperatureMonitor.cs:Monitoringnamespace に、publisher として機能するTemperatureMonitorclass を作成します。monitor には次の機能を持たせます。- current temperature を格納する private field を持つ
- temperature が更新されるたびに発生する、
TemperatureChangedcalled の event をAction<int>を使用して Declare する Temperatureproperty(int)を持ち、setter が private field を更新し、新しい temperature value とともに event を raise する
?.Invoke()pattern を使用することを忘れないでください。Program.cs:main file でTemperatureMonitorを作成し、そのTemperatureChangedevent に2つの異なる handler を Subscribe します。- 次を prints する handler:
Alert: Temperature is now {value} degrees - 次を prints する another handler:
Logged: {value}
- 次を prints する handler:
2つの input を受け取ります。
- First temperature value(integer)
- Second temperature value(integer)
たとえば、input が 25 と 30 の場合、output は次のようになります。
Alert: Temperature is now 25 degrees
Logged: 25
Alert: Temperature is now 30 degrees
Logged: 30Temperature property を設定すると、すべての subscriber に自動的に通知されることに注目してください。monitor は誰が listening しているかを知る必要がありません。これが event-driven approach の魅力です。
自分で試してみよう
using System;
using Monitoring;
class Program
{
public static void Main(string[] args)
{
// 入力を読み取る
int temp1 = Convert.ToInt32(Console.ReadLine());
int temp2 = Convert.ToInt32(Console.ReadLine());
// TODO: TemperatureMonitor のインスタンスを作成する
// TODO: Subscribe a handler that prints: "Alert: Temperature is now {value} degrees"
// TODO: "Logged: {value}" を出力する別のハンドラーを購読する
// TODO: 温度を temp1 に設定する
// TODO: 温度を temp2 に設定する
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
5ポリモーフィズムとインターフェース
コンパイル時 vs 実行時ポリモーフィズムインターフェース vs 抽象クラス複数のインターフェース明示的なインターフェースアップキャストとダウンキャストまとめ - 図形計算機8オブジェクト指向の高度な概念
継承よりコンポジションジェネリクス (クラスとメソッド)デリゲートとイベント属性とリフレクションIDisposable と using ステートメント依存性の注入 (DI) の基礎自分で練習してみよう: C#オンラインコンパイラ