C#入門:Actionで学ぶ「メソッドを変数にする」仕組み

〜型パラメータなしから Action<string>、WinForms応用まで〜


はじめに

C# を学び始めた方にとって、「メソッドを変数のように扱える」 というのは直感的にわかりづらいかもしれません。

しかし、これを理解すると イベント処理 や 疎結合な設計 に大きく役立ちます。

この記事では、まず 型パラメータなしの Action から始めて、

→ Action<string> に進み、

→ 最後に WinForms アプリでのログ通知サンプル まで解説します。


1. Action(型パラメータなし)とは?

C# には「デリゲート(delegate)」という、メソッドを変数のように扱える仕組み があります。

そのうち、戻り値が void で引数がないメソッド を入れられるのが Action です。

サンプルコード

using System;

class Program
{
    static void Main()
    {
        Action act; // 宣言

        // 通常メソッドを代入
        void Hello() => Console.WriteLine("Hello, Action!");
        act = Hello;

        act();           // 実行
        // act.Invoke(); // 同じ意味
    }
}

実行結果

Hello, Action!

👉 ポイント:Action は「引数なし・戻り値なし」のメソッドを入れられる変数。


2. 無名メソッド・ラムダ式を使う

メソッドをいちいち用意しなくても、その場で処理を書くこともできます。

Action a1 = delegate { Console.WriteLine("無名メソッド"); };
Action a2 = () => Console.WriteLine("ラムダ式");

a1();
a2();

3. 複数メソッドを登録する

Action は イベント風 に「あとから処理を足す」ことが可能です。

Action pipe = null!;
pipe += () => Console.WriteLine("Step 1");
pipe += () => Console.WriteLine("Step 2");

pipe(); // Step1, Step2 の両方が実行される

👉 この 「追加できる」性質 が、のちの イベント処理 に直結します。


4. Action<T> に拡張する

次に 引数あり の Action<T> を見てみましょう。

ここから実用度が一気に上がります。

例:Action<string>

Action<string> logger;

void PrintLog(string msg) => Console.WriteLine("[LOG] " + msg);
logger = PrintLog;

logger("メッセージを渡せる!");

実行結果

[LOG] メッセージを渡せる!

👉 ポイント

  • Action<T> は「引数 T を受け取る、戻り値なしのメソッド」を表す
  • Action<int>, Action<double> なども可能

5. 応用:複数処理をまとめる

+= を使えば、複数の処理を一度に呼べるようになります。

Action<string> log = msg => Console.WriteLine(msg);
log += msg => System.IO.File.AppendAllText("app.log", msg + Environment.NewLine);

log("同時にコンソールとファイルへ出力!");

6. WinForms でログ通知に使う

ここまで学んだら、実際の Windowsアプリ(WinForms) に応用してみましょう。

「攻撃」「回復」ボタンを押すと、テキストボックスにログが溜まっていくシンプルなサンプルです。

6-1. フォームの準備

  • Button ×2
    • btnAttack(テキスト: 攻撃)
    • btnHeal(テキスト: 回復)
  • TextBox ×1
    • txtLog(Multiline = true, ReadOnly = true, ScrollBars = Vertical)

6-2. コード

using System;
using System.Windows.Forms;

namespace ActionWinFormsSample
{
    public partial class Form1 : Form
    {
        private Action<string>? Log; // ログ出力先

        private int playerHp = 30;
        private int enemyHp  = 20;

        public Form1()
        {
            InitializeComponent();

            // ログの送り先を設定(UI表示)
            Log = msg => txtLog.AppendText(msg + Environment.NewLine);

            // 追加でファイル保存も可能
            // Log += msg => System.IO.File.AppendAllText("game.log", msg + "\n");
        }

        private void btnAttack_Click(object sender, EventArgs e)
        {
            enemyHp = Math.Max(0, enemyHp - 5);
            Log?.Invoke($"プレイヤーが攻撃! 敵HP: {enemyHp}");

            if (enemyHp == 0) Log?.Invoke("敵を倒した!");
        }

        private void btnHeal_Click(object sender, EventArgs e)
        {
            playerHp = Math.Min(30, playerHp + 5);
            Log?.Invoke($"プレイヤーは回復! 自分HP: {playerHp}");
        }
    }
}

実行イメージ

プレイヤーが攻撃! 敵HP: 15
プレイヤーが回復! 自分HP: 30
敵を倒した!

7. まとめ

  • Action:引数なし・戻り値なしのメソッドを入れられる
  • Action<T>:引数ありに拡張できる
  • +=:処理をどんどん足していける(イベント風の使い方)
  • WinForms応用:UIログ出力・ファイル保存を柔軟に切り替え可能

👉 「メソッドを変数にする」ことを理解すると、イベント通知・疎結合な設計 に自然とつながります。

訪問数 3 回, 今日の訪問数 3回