bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] デリゲートを理解する: デリゲート型の基本

[C#] デリゲートを理解する: デリゲート型の基本

Jun 13, 2026 C# , .NET bucket-sort

前回までは、WPF の XAML 構文について見てきました。

今回からは、C# のデリゲートを整理します。

デリゲートは、イベント、ラムダ式、LINQ、コールバックなど、C# のさまざまな機能の土台になる仕組みです。

最初は少し抽象的に見えますが、まずは「メソッドを変数のように扱うための型」と考えると理解しやすくなります。

デリゲート型とは

デリゲート型は、メソッドを参照するための型です。

たとえば、次のようなメソッドがあるとします。

static void SayHello()
{
    Console.WriteLine("Hello");
}

通常は次のように直接呼び出します。

SayHello();

デリゲートを使うと、この SayHello メソッドを変数に入れて、あとから呼び出せます。

MessageHandler handler = SayHello;
handler();

つまりデリゲートは、次のような場面で使えます。

  • あとで呼び出す処理を渡したい
  • 処理の中身を外部から差し替えたい
  • ある処理が終わったあとに呼ぶコールバックを渡したい
  • 複数の通知先をまとめて呼び出したい

デリゲート型の定義方法

デリゲート型は、delegate キーワードで定義します。

delegate void MessageHandler();

これは、次の形のメソッドを参照できるデリゲート型です。

  • 戻り値が void
  • 引数がない

完全な例を見てみます。

using System;

delegate void MessageHandler();

class Program
{
    static void Main()
    {
        MessageHandler handler = ShowMessage;

        handler();
    }

    static void ShowMessage()
    {
        Console.WriteLine("メッセージを表示します");
    }
}

実行結果は次のようになります。

メッセージを表示します

MessageHandler に代入できるのは、void を返し、引数を取らないメソッドです。

デリゲート型は、参照できるメソッドの形を決める型だと考えるとよいでしょう。

引数を持つデリゲート

引数を持つデリゲートも定義できます。

delegate void LogHandler(string message);

このデリゲートには、string を 1 つ受け取り、戻り値が void のメソッドを代入できます。

using System;

delegate void LogHandler(string message);

class Program
{
    static void Main()
    {
        LogHandler logger = WriteLog;

        logger("処理を開始しました");
    }

    static void WriteLog(string message)
    {
        Console.WriteLine($"LOG: {message}");
    }
}

実行結果です。

LOG: 処理を開始しました

デリゲートを呼び出すと、実際には代入されている WriteLog メソッドが呼び出されます。

戻り値を持つデリゲート

戻り値を持つデリゲートも定義できます。

delegate int Calculator(int x, int y);

これは、int を 2 つ受け取り、int を返すメソッドを参照できます。

using System;

delegate int Calculator(int x, int y);

class Program
{
    static void Main()
    {
        Calculator calculator = Add;

        int result = calculator(10, 20);

        Console.WriteLine(result);
    }

    static int Add(int x, int y)
    {
        return x + y;
    }
}

実行結果です。

30

デリゲートに代入できるメソッドは、戻り値と引数の型が一致している必要があります。

最もシンプルなデリゲート例

最小限のデリゲート例は、次のようになります。

using System;

delegate void SimpleDelegate();

class Program
{
    static void Main()
    {
        SimpleDelegate d = Hello;

        d();
    }

    static void Hello()
    {
        Console.WriteLine("Hello Delegate");
    }
}

このコードでは、次の行でデリゲート型を定義しています。

delegate void SimpleDelegate();

そして、次の行で Hello メソッドをデリゲート変数に代入しています。

SimpleDelegate d = Hello;

最後に、デリゲート経由でメソッドを呼び出しています。

d();

見た目はメソッド呼び出しに似ていますが、呼び出している相手は Hello ではなく、Hello を参照しているデリゲート変数です。

デリゲートオブジェクトを深掘りする

デリゲートは、単なる関数ポインターではありません。

C# のデリゲートはオブジェクトです。そのため、自分が参照しているメソッドの情報を持っています。

using System;

delegate void MessageHandler();

class Program
{
    static void Main()
    {
        MessageHandler handler = ShowMessage;

        Console.WriteLine(handler.Method.Name);
        Console.WriteLine(handler.Target == null);
    }

    static void ShowMessage()
    {
        Console.WriteLine("Hello");
    }
}

実行結果の例です。

ShowMessage
True

handler.Method には、参照しているメソッドの情報が入っています。

handler.Method.Name

で、メソッド名を取得できます。

handler.Target には、インスタンスメソッドの場合、そのメソッドを持つオブジェクトが入ります。

今回の ShowMessage は static メソッドなので、Target は null です。

インスタンスメソッドを参照する

インスタンスメソッドをデリゲートに代入すると、Target には対象のオブジェクトが入ります。

using System;

delegate void MessageHandler();

class Messenger
{
    public void Show()
    {
        Console.WriteLine("インスタンスメソッドです");
    }
}

class Program
{
    static void Main()
    {
        Messenger messenger = new Messenger();

        MessageHandler handler = messenger.Show;

        handler();

        Console.WriteLine(handler.Method.Name);
        Console.WriteLine(handler.Target?.GetType().Name);
    }
}

実行結果です。

インスタンスメソッドです
Show
Messenger

この場合、デリゲートは次の情報を持っています。

  • どのオブジェクトを対象にするか
  • どのメソッドを呼び出すか

そのため、デリゲートは「メソッドだけ」を持っているのではなく、「対象オブジェクトとメソッドの組み合わせ」を持つことがあります。

System.Delegate ベースクラス

C# のすべてのデリゲート型は、内部的には System.Delegate を基底に持ちます。

ただし、開発者が次のように直接継承してデリゲートを作ることはできません。

// これはできない
class MyDelegate : Delegate
{
}

デリゲート型は、必ず delegate キーワードで定義します。

delegate void MyDelegate();

System.Delegate は、デリゲートが共通して持つ基本機能を提供します。

代表的なものは次の通りです。

メンバー 内容
Method 参照しているメソッド情報
Target インスタンスメソッドの対象オブジェクト
DynamicInvoke 実行時に引数を渡して呼び出す
GetInvocationList 呼び出し対象の一覧を取得する

DynamicInvoke を使うと、実行時に引数を渡してデリゲートを呼び出せます。

using System;

delegate void MessageHandler(string message);

class Program
{
    static void Main()
    {
        MessageHandler handler = Show;

        Console.WriteLine(handler.Method.Name);
        handler.DynamicInvoke("DynamicInvoke から呼び出し");
    }

    static void Show(string message)
    {
        Console.WriteLine(message);
    }
}

実行結果です。

Show
DynamicInvoke から呼び出し

ただし、通常は handler("message") のように直接呼び出します。

DynamicInvoke は型安全性が弱く、通常の呼び出しよりも遅いため、リフレクション的な処理が必要な場面以外ではあまり使いません。

System.MulticastDelegate クラス

通常、C# で定義したデリゲート型は System.MulticastDelegate を継承します。

概念的な継承関係は次のようになります。

System.Object
  └── System.Delegate
        └── System.MulticastDelegate
              └── 自分で定義したデリゲート型

MulticastDelegate の重要な特徴は、複数のメソッドを登録できることです。

using System;

delegate void NotifyHandler();

class Program
{
    static void Main()
    {
        NotifyHandler handler = First;
        handler += Second;
        handler += Third;

        handler();
    }

    static void First()
    {
        Console.WriteLine("First");
    }

    static void Second()
    {
        Console.WriteLine("Second");
    }

    static void Third()
    {
        Console.WriteLine("Third");
    }
}

実行結果です。

First
Second
Third

ひとつのデリゲート変数を呼び出すだけで、登録されたメソッドが順番に実行されています。

この仕組みは、次回扱う「状態変更の通知」やイベントの基礎になります。

まとめ

デリゲート型は、メソッドを参照するための型です。

  • delegate キーワードでデリゲート型を定義する
  • 戻り値と引数が一致するメソッドを代入できる
  • デリゲートはメソッドを参照するオブジェクトである
  • Method で参照先メソッドを確認できる
  • Target でインスタンスメソッドの対象オブジェクトを確認できる
  • すべてのデリゲート型は System.Delegate を基底に持つ
  • 通常のデリゲート型は System.MulticastDelegate により複数メソッドを登録できる

次回は、デリゲートを使ってオブジェクトの状態変化を通知する方法を見ていきます。

C# .NET Delegate デリゲート Method Group
← [C#] ポインター実践例② — P/Invoke を使った C++ DLL との相互運用 [C#] デリゲートを理解する: 状態通知とマルチキャスト →

Related Posts

  • [C#] デリゲートを理解する: Action と Func Jun 15, 2026
  • [C#] デリゲートを理解する: 状態通知とマルチキャスト Jun 14, 2026
  • [C#] LINQ to Objects を理解する: クエリの内部表現 Jun 22, 2026
  • [C#] ラムダ式を理解する Jun 18, 2026

Table of Contents

  • デリゲート型とは
  • デリゲート型の定義方法
  • 引数を持つデリゲート
  • 戻り値を持つデリゲート
  • 最もシンプルなデリゲート例
  • デリゲートオブジェクトを深掘りする
  • インスタンスメソッドを参照する
  • System.Delegate ベースクラス
  • System.MulticastDelegate クラス
  • まとめ

Recent Posts

  • [C#] プラグインで拡張できるアプリケーションを設計する Jul 9, 2026
  • [C#] 属性でコードに意味を与える Jul 8, 2026
  • [C#] 外部アセンブリを読み込み実行時に型を呼び出す Jul 7, 2026
  • [C#] リフレクションで型の中身を調べる Jul 6, 2026
  • [C#] 型メタデータとリフレクションの基礎を理解する Jul 5, 2026

Categories

  • C#120
  • .NET119
  • AWS27
  • Laravel16
  • Linux15
  • MySQL9
  • Apache8
  • PHP8
  • DynamoDB6
  • セキュリティ6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • .NET Framework1
  • Aurora1
  • Diagnostics1
  • Filament1
  • Git1
  • SQS1

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • コレクション
  • PHP
  • セキュリティ
  • MySQL
  • Linux
  • パフォーマンス
  • Apache
  • System.Collections.Generic
  • デリゲート
  • Code Snippet
  • DynamoDB
  • LINQ
  • NoSQL
  • PHP-FPM
  • RDS
  • System.Collections
  • Windows
  • メモリ管理
  • リフレクション
  • DoS
  • Nginx
  • WordPress
  • メタデータ
  • ラムダ式
  • 監視
  • 設計
  • Amazon Linux 2023
  • Delegate
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • LINQ to Objects
  • OPCache
  • Pointer
  • Reflection
  • System.Collections.Specialized
  • Unsafe
  • Webサーバー
  • インターフェース
  • オブジェクト指向
  • クラス設計
  • デザインパターン
  • パターンマッチング
  • ポインター
  • 継承
Powered by Hugo & Explore Theme.