【Unity・C#】ActionとFuncについてまとめる

私事ですが、ActionFuncを使用する頻度が増えてきました。
しっかりと認識したことがなかったためメモを残しておきます。

対応表

すべて using System; を使用します。

型構文 説明
Action 戻り値なし・引数なし
Action<T, ..., > 戻り値なし・引数あり
Func<TResult> 戻り値あり・引数なし
Func<T, ..., TResult> 戻り値あり・引数あり

基本的な使い方

ActionFunc「関数を参照するための型」です。
まずは一例を載せておきます。

using System;
using UnityEngine;

public class SampleComponent: MonoBehaviour
{
    //-----------------------------------------------------------------------
    // メンバ変数
    //-----------------------------------------------------------------------

    // 1: Action型の変数を定義
    private Action m_Action;

    //-----------------------------------------------------------------------
    // Unityメゾット
    //-----------------------------------------------------------------------

    // 初期化処理
    private void Start()
    {
        // 2: m_ActionにShowLog()関数の参照を渡す
        m_Action += ShowLog;
    }

    // 更新処理
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // 3: m_Action.Invoke()で参照させた関数が呼ばれる
            //    →ShowLog()が呼ばれる
            m_Action.Invoke();
        }
    }

    // 破壊時
    private void OnDestroy()
    {
        // 4:使い終わったら参照を消す
        m_Action-= ShowLog;
    }

    //-----------------------------------------------------------------------
    // 内部メゾット
    //-----------------------------------------------------------------------

    // ログ表示
    private void ShowLog()
    {
        Debug.Log("Hello World!");
    }
}

メンバ変数に対して+=【関数】で登録します。
任意のタイミングでInvoke()を呼んで関数を実行できます。
使わなくなったら-=【関数】で解除おきましょう。

気づいた方もいるかもしれませんが、
+=や-=などを使って、関数の登録/解除を視覚的に分かりやすくしてくれています。
普段の計算式のように扱えるのはevent君のおかげですね。
ありがたや…。ありがたや…。 learn.microsoft.com

また、「関数を参照するための型」なので引数にもできたりします。

using System;
using UnityEngine;

// サンプルコンポーネント
public class SampleComponent: MonoBehaviour
{
    //-----------------------------------------------------------------------
    // メンバ変数
    //-----------------------------------------------------------------------

    private ExecuteInsteadComponent m_ExeComp = null;

    //-----------------------------------------------------------------------
    // Unityメゾット
    //-----------------------------------------------------------------------

    // 初期化処理
    private void Start()
    {
        // 1: 実行を行うコンポーネント
        m_ExeComp = GetComponent<ExecuteInsteadComponent >();
    }

    // 更新処理
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // 2: 引数に自身の関数を渡す
            m_ExeComp .InsteadFunction(ShowLog);
        }
    }

    //-----------------------------------------------------------------------
    // 内部メゾット
    //-----------------------------------------------------------------------

    // ログ表示
    private void ShowLog()
    {
        Debug.Log("Hello World!");
    }
}
using System;
using UnityEngine;

// 代わりに関数を実行するコンポーネントクラス
public class ExecuteInsteadComponent : MonoBehaviour
{
    // 3: 関数実行
    //     →SampleComponentのShowLog()を処理
    public void InsteadFunction(Action action)
    {
        action.Invoke();
    }
}

SampleComponentでは処理を行わず、
ExecuteInsteadComponent側で処理をさせるサンプルです。
private関数でも関係なく実行が可能です。

Action Delegate

ActionAction<T>は、「戻り値を持たない関数を参照するための型」です。

Action

戻り値なし・引数を持たない関数はこちら。

日本語訳だとAction代理人となっていますが、
デリゲートと覚えてしまった方がよいです。 learn.microsoft.com

using System;
using UnityEngine;

// Actionのサンプル
public class SampleComponent : MonoBehaviour
{
    //-----------------------------------------------------------------------
    // Unityメゾット
    //-----------------------------------------------------------------------

    // 更新処理
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // 関数を渡して実行
            ActionExecute(ShowLog);
        }
    }

    //-----------------------------------------------------------------------
    // 内部メゾット
    //-----------------------------------------------------------------------

    // Action実行
    // void Hoge() と同じ
    private void ActionExecute(Action action)
    {
        action.Invoke();
    }

    // ログ表示
    private void ShowLog()
    {
        Debug.Log("Hello World!");
    }
}

Action<T>

戻り値なし・引数を持つ関数はこちら。

Actionの後の<>の中に型を入れることで
引数付きの関数を入れられるようになります。
Invokeの()内に自分で記述した引数を入れる感じです。 learn.microsoft.com

using System;
using UnityEngine;

// Action<T>のサンプル
public class SampleComponent : MonoBehaviour
{
    //-----------------------------------------------------------------------
    // Unityメゾット
    //-----------------------------------------------------------------------

    // 更新処理
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // 関数を渡して実行
            ActionExecute(ShowLog);
        }
    }

    //-----------------------------------------------------------------------
    // 内部メゾット
    //-----------------------------------------------------------------------

    // Action<T>実行
    // void Hoge(int value1) と同じ
    private void ActionExecute(Action<int> action)
    {
        action.Invoke(0);
    }

    // ログ表示
    private void ShowLog(int value1,int value2)
    {
        Debug.Log("Value1 : "+ value1);
    }
}
引数の数について

ちなみに引数に持っていける数は最大で16個です。
(そんなにいる…?) learn.microsoft.com

Func Delegate

Func<TResult>・Func<T,TResult>は、「戻り値を持つ関数を参照するための型」です。

Func<TResult>

戻り値あり・引数を持たない関数はこちら。

Action<T>とは違い、<>の中に入れた型がそのまま戻り値となります。 learn.microsoft.com

using System;
using UnityEngine;

// Func<TResult>のサンプル
public class SampleComponent : MonoBehaviour
{
    //-----------------------------------------------------------------------
    // Unityメゾット
    //-----------------------------------------------------------------------

    // 更新処理
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // 関数を渡して実行
            FuncExecute(GetFlg);
        }
    }

    //-----------------------------------------------------------------------
    // 内部メゾット
    //-----------------------------------------------------------------------

    // Func実行
    // bool Hoge() と同じ
    private void FuncExecute(Func<bool> func)
    {
        bool flg = func.Invoke();

        if (flg)
        {
            Debug.Log("Hello World!");
        }
    }

    // trueを返す関数
    private bool GetFlg()
    {
        return true;
    }
}

Func<T,TResult>

戻り値あり・引数を持つ関数はこちら。

こちらは引数の数にかかわらず、
一番最後に入れた型が戻り値となります。 learn.microsoft.com

using System;
using UnityEngine;

// Func<TResult,T>のサンプル
public class SampleComponent : MonoBehaviour
{
    //-----------------------------------------------------------------------
    // Unityメゾット
    //-----------------------------------------------------------------------

    // 更新処理
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // 関数を渡して実行
            FuncExecute(GetFlg);
        }
    }

    //-----------------------------------------------------------------------
    // 内部メゾット
    //-----------------------------------------------------------------------

    // Func実行
    // bool Hoge(int value) と同じ
    private void FuncExecute(Func<int,bool> func)
    {
        bool flg = func.Invoke(1);

        if (flg)
        {
            Debug.Log("Hello World!");
        }
    }

    // trueを返す関数
    private bool GetFlg(int value)
    {
        bool ret = false;

        if (value >= 0)
        {
            ret = true;
        }

        return ret;
    }
}
引数の数について

こちらもAction<T>と同じく、引数に持っていける数は最大で16個です。
どれだけ引数があろうと一番最後が戻り値となります。 learn.microsoft.com

参考にしたもの

デリゲートとイベント | Microsoft Learn
厳密に型指定されたデリゲート | Microsoft Learn
標準的な .NET イベント パターン | Microsoft Learn
Delegate クラス (System) | Microsoft Learn
event - C# リファレンス | Microsoft Learn
Action 代理人 (System) | Microsoft Learn
https://learn.microsoft.com/ja-jp/dotnet/api/system.func-1?view=net-7.0