Menu
Coddy logo textTech

デリゲートとイベント

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 アプリケーション、ゲームエンジン、およびオブジェクトが密結合せずに変更へ反応する必要があるあらゆるシステムの基本です。

challenge icon

チャレンジ

簡単

温度が変化するたびに delegate とイベントを使用して subscriber に通知する、温度監視システムを構築しましょう。これは、イベントによって非常に優雅に実現できる publish-subscribe パターンの典型的な例です。

コードを2つのファイルに分けて整理します。

  • TemperatureMonitor.csMonitoring namespace に、publisher として機能する TemperatureMonitor class を作成します。monitor には次の機能を持たせます。
    • current temperature を格納する private field を持つ
    • temperature が更新されるたびに発生する、TemperatureChanged called の event を Action<int> を使用して Declare する
    • Temperature property(int)を持ち、setter が private field を更新し、新しい temperature value とともに event を raise する
    subscriber が存在する場合にのみ event を safely raise するため、?.Invoke() pattern を使用することを忘れないでください。
  • Program.cs:main file で TemperatureMonitor を作成し、その TemperatureChanged event に2つの異なる handler を Subscribe します。
    • 次を prints する handler:Alert: Temperature is now {value} degrees
    • 次を prints する another handler:Logged: {value}
    両方の handler を Subscribe した後、input の values を使用して temperature を2回設定します。temperature を設定するたびに、両方の handler が応答する必要があります。

2つの input を受け取ります。

  • First temperature value(integer)
  • Second temperature value(integer)

たとえば、input が 2530 の場合、output は次のようになります。

Alert: Temperature is now 25 degrees
Logged: 25
Alert: Temperature is now 30 degrees
Logged: 30

Temperature 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 に設定する
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: C#オンラインコンパイラ