基礎から学ぶC#入門 90日コース | 実践力を高める - Day 67:イベントの基礎

Web APP 90日で身につけるC#
スポンサーリンク
スポンサーリンク

Day 67 のゴールと全体像

Day 67 では、C# の「仕組みを理解すると一気に世界が広がる」テーマ、イベントの基礎をじっくり学んでいきます。 今日のキーワードはこの2つです。

  • イベント
  • delegateとの関係

イベントは、ボタンがクリックされたとき、ファイルの読み込みが終わったとき、 ゲームで敵が倒されたとき…など、「何かが起きた瞬間」を扱うための仕組みです。

そして、そのイベントの裏側で動いているのが delegate(デリゲート) です。 ここを理解しておくと、C# のコードがぐっと“立体的”に見えるようになります。

この記事では、

  • イベントとは何か
  • delegate とイベントの関係
  • 自作イベントの作り方
  • イベントの発火と購読の流れ
  • 実践的なテンプレート

を、ステップバイステップでかみ砕いて解説していきます。

イベントとは何かをイメージでつかむ

「何かが起きたら呼んでね」という仕組み

イベントは、ひと言でいうと 通知の仕組み です。

あるオブジェクトが「○○が起きたよ!」と知らせる → その通知を受け取った側が、登録しておいた処理を実行する

という流れで動きます。

たとえば、ボタンのクリックをイメージしてみてください。

  • ボタン(イベントを発行する側)が「クリックされたよ!」と知らせる
  • 登録していたメソッド(イベントを受け取る側)が呼ばれる

この「登録しておくメソッド」が delegate であり、 「通知を送る仕組み」が event です。

イベントが活躍する場面

イベントは、次のような場面でよく使われます。

  • GUIアプリ
    • ボタンが押された
    • テキストが変更された
  • ゲーム
    • プレイヤーがダメージを受けた
    • ステージクリア
  • 非同期処理
    • ダウンロード完了
    • タスクの終了通知

「何かが起きた瞬間に反応したい」というとき、 イベントはとても自然な形でコードを組み立てることができます。

delegate とイベントの関係

delegate は「メソッドの型」

まずは、delegate の役割を整理しておきます。

delegate は、

「こういう形のメソッドを登録できますよ」という“メソッドの型”

です。

たとえば、

// string を受け取って、何も返さないメソッドを表す delegate 型
public delegate void Notify(string message);
C#

これは、

  • 引数:string message
  • 戻り値:void

という形のメソッドを表す「型」です。

この delegate 型を使うと、

public class Notifier
{
    public Notify Handler; // メソッドを入れておける変数
}
C#

のように、「メソッドを入れておく変数」を作ることができます。

event は「delegate を使った通知システム」

イベントは、この delegate をベースにして作られます。

public class Notifier
{
    public delegate void Notify(string message);

    // イベントの定義
    public event Notify OnNotified;
}
C#

ここでのポイントは、

  • Notify が「イベントに登録できるメソッドの型」
  • event Notify OnNotified; が「そのメソッドを登録しておくイベント」

という関係になっていることです。

つまり、

  • delegate:メソッドの型
  • event:その delegate を使って通知を送る仕組み

という構造になっています。

まずは delegate だけで「イベントっぽい動き」を見てみる

イベントの理解を深めるために、 まずは event を使わず、delegate だけで「イベント風の動き」を作ってみます。

using System;

class Program
{
    // 通知用の delegate 型
    delegate void Notify(string message);

    static void Main()
    {
        // 通知を受け取るメソッドを登録
        Notify notifier = OnNotified;

        // 作業をして、終わったら通知する
        DoWork(notifier);
    }

    // 長い作業をするメソッド
    static void DoWork(Notify notify)
    {
        Console.WriteLine("作業中…");
        System.Threading.Thread.Sleep(1000); // 1秒待つ(長い処理のイメージ)

        // 作業完了を通知
        notify("作業が完了しました!");
    }

    // 通知を受け取るメソッド
    static void OnNotified(string message)
    {
        Console.WriteLine($"通知: {message}");
    }
}
C#

このコードでは、

  • Notify delegate が「通知用メソッドの型」
  • DoWork が「通知を送る側」
  • OnNotified が「通知を受け取る側」

という関係になっています。

ただし、このままだと、

  • 誰でも notifier を書き換えられる
  • 複数のメソッドを登録する仕組みがない
  • 外部から勝手に notify("…") を呼べてしまう

など、少し危うい状態です。

そこで登場するのが event です。

event を使って「安全な通知システム」にする

event の基本形

イベントは、delegate をベースにして次のように定義します。

public delegate void Notify(string message);

public event Notify OnCompleted;
C#

この event を付けることで、

  • 外部から勝手にイベントを発火できない
  • 外部から勝手にイベントを消せない(= で上書きできない)
  • += で複数のメソッドを登録できる

という、安全で扱いやすい仕組みになります。

イベントを自分で作ってみる

ここからは、 「イベントを持つクラス」「イベントを購読する側」 を セットで作っていきます。

ステップ1:イベントを持つクラスを定義する

using System;

public class Worker
{
    // 1. delegate 型の定義
    public delegate void Notify(string message);

    // 2. event の定義
    public event Notify OnCompleted;

    // 3. 作業をするメソッド
    public void DoWork()
    {
        Console.WriteLine("作業中…");
        System.Threading.Thread.Sleep(1000); // 1秒待つ

        Console.WriteLine("作業が終わりました。");

        // 4. イベントを発火(通知)
        OnCompleted?.Invoke("作業が正常に完了しました。");
        // OnCompleted が null でなければ Invoke する、という安全な書き方です。
    }
}
C#

ここでのポイントは、

  • Notify delegate が「イベントに登録できるメソッドの型」
  • event Notify OnCompleted; が「作業完了を通知するイベント」
  • OnCompleted?.Invoke("…") が「イベントを発火するコード」

という構造になっていることです。

ステップ2:イベントを購読する側を作る

using System;

class Program
{
    static void Main()
    {
        Worker worker = new Worker();

        // イベント購読(登録)
        worker.OnCompleted += OnWorkCompleted;

        // 作業開始
        worker.DoWork();
    }

    // イベントが発火されたときに呼ばれるメソッド
    static void OnWorkCompleted(string message)
    {
        Console.WriteLine($"イベント受信: {message}");
    }
}
C#

ここでは、

  • worker.OnCompleted += OnWorkCompleted;
    • 「作業が終わったら OnWorkCompleted を呼んでね」と登録している
  • DoWork() の中でイベントが発火されると、
    • OnWorkCompleted が呼ばれてメッセージを表示する

という流れになっています。

実行イメージ

作業中…
作業が終わりました。
イベント受信: 作業が正常に完了しました。

この「イベントを持つクラス」と「イベントを購読する側」の関係が、 イベントの基本パターンです。

イベントの流れを整理してみる

イベントの4ステップ

  1. delegate 型を定義するcsharppublic delegate void Notify(string message);
  2. event を定義するcsharppublic event Notify OnCompleted;
  3. イベントを発火する(通知する)csharpOnCompleted?.Invoke("完了しました!");
  4. イベントを購読(登録)するcsharpworker.OnCompleted += OnWorkCompleted;

この4ステップを押さえておくと、 イベントのコードがぐっと読みやすくなります。

イベントは複数のメソッドを登録できる

イベントの便利なところは、 複数のメソッドを登録できる ことです。

worker.OnCompleted += msg => Console.WriteLine("A: " + msg);
worker.OnCompleted += msg => Console.WriteLine("B: " + msg);
worker.OnCompleted += msg => Console.WriteLine("C: " + msg);
C#

この状態でイベントが発火すると、

  • A の処理
  • B の処理
  • C の処理

が、登録された順番にすべて呼ばれます。

これは、

「ひとつの出来事に対して、複数の反応をまとめて登録しておける」

というイメージです。

イベントのミニテンプレート

最後に、Day 67 で使える「イベントの基本テンプレート」をまとめておきます。

イベントを持つクラスのテンプレート

public class Something
{
    // イベント用 delegate 型
    public delegate void Notify(string message);

    // イベントの定義
    public event Notify OnHappened;

    public void DoSomething()
    {
        Console.WriteLine("何かの処理をしています…");

        // ここで何かが起きたと仮定
        Console.WriteLine("何かが起きました!");

        // イベント発火
        OnHappened?.Invoke("Something のイベントが発生しました。");
    }
}
C#

イベントを購読する側のテンプレート

class Program
{
    static void Main()
    {
        var s = new Something();

        // イベント購読(ラムダ式で登録)
        s.OnHappened += message =>
        {
            Console.WriteLine($"イベント受信: {message}");
        };

        // 処理を実行
        s.DoSomething();
    }
}
C#

delegate と event の関係をもう一度まとめる

delegate

  • 役割: メソッドの型を表す
  • 「こういう形のメソッドを登録できますよ」という宣言
  • 例:public delegate void Notify(string message);

event

  • 役割: delegate を使った通知システム
  • 「登録されたメソッドを安全に呼び出す仕組み」
  • 外部から勝手に発火できない(安全性アップ)
  • += で複数のメソッドを登録できる

イメージ

  • delegate:「招待状のフォーマット」
  • event:「招待状を配って、集まった人たちに一斉に知らせる仕組み」

というようにイメージしてもらうと、 イベントの役割がぐっとつかみやすくなると思います。

Day 67 のまとめ

Day 67 では、

  • イベントとは「何かが起きたときに呼ばれる通知の仕組み」であること
  • delegate は「イベントに登録できるメソッドの型」であること
  • event は「delegate を使った安全な通知システム」であること
  • イベントは複数のメソッドを登録できること
  • イベントの4ステップ(定義 → 発火 → 購読 → 実行)

を、例題コードとともに見てきました。

イベントは、GUI・ゲーム・非同期処理・ライブラリ設計など、 実践的なプログラミングのあらゆる場面で登場する、とても重要な概念です。

ぜひ、

  • 自分でイベントを持つクラスを書いてみる
  • 複数のメソッドをイベントに登録してみる
  • ラムダ式でイベント購読を書いてみる

といった小さな練習を重ねながら、 イベントの仕組みを「自分の武器」として、 少しずつ体に馴染ませていっていただければうれしいです。

タイトルとURLをコピーしました