C# におけるイベント処理入門(基本)

1. はじめに

C# のイベントは、「ある出来事」が発生したときに、あらかじめ登録したメソッド(ハンドラ)を自動的に実行する仕組みです。イベントの仕組みを理解するためには、まず「デリゲート」という概念を押さえる必要があります。ここでは、以下の 2 つの方法でイベントのサンプルを示します。

  • カスタムデリゲート型を利用したサンプル
    → イベントの仕組みの内部(どのように型が定義され、イベントとして利用されるか)を理解できます。
  • 組み込みデリゲート型(EventHandler/Action)を利用したサンプル
    → Microsoft が推奨する実践的な方法を学び、コードをシンプルに保つ方法が理解できます。

2. イベントとデリゲートの基本

  • イベントとは
    イベントは、たとえば GUI のボタンをクリックしたときなど、特定の「出来事」が発生した際に登録されたメソッドを自動的に呼び出す仕組みです。
  • デリゲートとは
    デリゲートは、メソッドへの参照を保持するための型です。イベントはこのデリゲートを基に実装され、メソッドのシグネチャ(引数や戻り値の型)を定義します。
  • 組み込みデリゲートの活用
    C# では、カスタムデリゲート型の定義の代わりに、標準で用意された ActionEventHandler、および EventHandler を使うことが推奨されています。これによりコードがよりシンプルになり、公式ドキュメントに沿った実装が可能です。

3. イベントの流れと役割

イベント処理の基本フローは次の通りです。

  1. イベントを定義するクラス(イベント送信側)
    デリゲート型(カスタムまたは組み込み)を用いてイベントを宣言し、必要なタイミングでイベントを発生させます。
  2. イベントを処理するクラス(イベント処理側)
    別のクラスがイベントに対してハンドラを登録し、イベント発生時にそのハンドラが自動的に実行されます。

4. サンプルコード:カスタムデリゲート型を利用した例

以下は、カスタムデリゲート型を定義してイベントを実装するシンプルなサンプルです。

using System;

namespace CustomDelegateSample
{
    // イベント送信側のクラス
    public class EventSender
    {
        // 1. カスタムデリゲート型の定義(引数は string 型、戻り値は void)
        public delegate void MyEventHandler(string message);

        // 2. イベントの宣言
        public event MyEventHandler SomethingHappened;

        // 3. イベントを発生させるメソッド
        public void DoSomething()
        {
            Console.WriteLine("DoSomething メソッドが呼ばれました。");
            // 登録されたハンドラがある場合にイベントを発生させる
            SomethingHappened?.Invoke("イベントが発生しました!");
        }
    }

    // イベント処理側のクラス
    public class EventReceiver
    {
        // イベントハンドラメソッド
        public void OnSomethingHappened(string message)
        {
            Console.WriteLine("EventReceiver でイベント受信: " + message);
        }
    }

    // エントリーポイント
    class Program
    {
        static void Main()
        {
            EventSender sender = new EventSender();
            EventReceiver receiver = new EventReceiver();

            // イベントハンドラの登録
            sender.SomethingHappened += receiver.OnSomethingHappened;

            // イベントの発生
            sender.DoSomething();

            Console.WriteLine("Enterキーを押して終了...");
            Console.ReadLine();
        }
    }
}

解説

  • カスタムデリゲート型の定義
    public delegate void MyEventHandler(string message); により、引数として文字列を受け取るメソッドの型を定義しています。
  • イベントの宣言と発生
    SomethingHappened イベントを宣言し、SomethingHappened?.Invoke(...) によって安全にイベントを発生させています。
  • ハンドラの登録
    受信側でメソッドをイベントに登録することで、イベント発生時にそのメソッドが呼ばれます。

5. サンプルコード:組み込みデリゲート型(EventHandler)を利用した例

次は、Microsoft が推奨する EventHandler を用いた実装例です。ここでは、追加情報を渡すためにカスタムの EventArgs クラスを利用します。

using System;

namespace BuiltInDelegateSample
{
    // カスタムイベント引数クラス(EventArgs を継承)
    public class MessageEventArgs : EventArgs
    {
        public string Message { get; set; }
    }

    // イベント送信側のクラス
    public class EventProducer
    {
        // EventHandler<TEventArgs> を使ってイベントを宣言
        public event EventHandler<MessageEventArgs> SomethingHappened;

        // イベントを発生させるメソッド
        public void DoSomething()
        {
            Console.WriteLine("DoSomething メソッドが呼ばれました。");
            // 登録されたハンドラがある場合にイベントを発生させる
            SomethingHappened?.Invoke(this, new MessageEventArgs { Message = "イベントが発生しました!" });
        }
    }

    // イベント処理側のクラス
    public class EventConsumer
    {
        // イベントハンドラメソッド(標準シグネチャ:object sender, MessageEventArgs e)
        public void OnSomethingHappened(object sender, MessageEventArgs e)
        {
            Console.WriteLine("EventConsumer でイベント受信: " + e.Message);
        }
    }

    // エントリーポイント
    class Program
    {
        static void Main()
        {
            EventProducer producer = new EventProducer();
            EventConsumer consumer = new EventConsumer();

            // イベントハンドラの登録
            producer.SomethingHappened += consumer.OnSomethingHappened;

            // イベントの発生
            producer.DoSomething();

            Console.WriteLine("Enterキーを押して終了...");
            Console.ReadLine();
        }
    }
}

解説

  • 組み込み型の利用
    public event EventHandler<MessageEventArgs> SomethingHappened; のように宣言することで、標準的なシグネチャ(object sender, MessageEventArgs e)のイベントが定義されます。
  • カスタム EventArgs クラス
    MessageEventArgs クラスにより、イベントで渡すメッセージなどの情報を保持できます。必要に応じてプロパティを拡張可能です。
  • イベントの発生とハンドラの登録
    built-in 型を利用することで、コードがシンプルになり、公式推奨の実装方法に沿った形となります。

6. まとめと比較

学習効果について

  • カスタムデリゲート型のサンプル
    イベントの基本概念や、デリゲート型がどのように定義・利用されるかを深く理解するのに役立ちます。内部の仕組みを把握するための学習材料として優れています。
  • 組み込みデリゲート型のサンプル
    Microsoft が推奨する方法に沿っており、実務でよく利用される実装方法を学ぶことができます。コードがシンプルで保守性が高い点も理解できるでしょう。

結論

両方のサンプルを学習することで、イベント処理の基礎から実践まで幅広く理解でき、実際の開発現場で柔軟に対応できる知識を得ることができます。初学者はまずカスタムデリゲート型で内部の仕組みを学び、その後、組み込み型のサンプルで実務向けのベストプラクティスを習得するとよいでしょう。


この資料をもとに、まずは各サンプルを手元で動かしてみて、イベントの発生と処理の流れを体感してみてください。

C#,イベント

Posted by hidepon