Tsuの雑記¯\_(ツ)_/¯

主に製作メモ・備忘録として使用。製作したアプリのリンクもあります。

【Unity】型パラメータありデリゲートのパラメータ化【C#】

型パラメータを持ったAction<T>のようなデリゲートも,メソッドのパラメータに指定する事が出来ます。

(Unity 2019.4.17f1 Personal)


始めに

前回の記事で,型パラメータなしデリゲートのパラメータ化を取り上げました。

tsu-games.hatenablog.com

今回は,型パラメータありデリゲートのパラメータ化について御説明いたします。


型パラメータありデリゲートのパラメータ化例

「任意の処理の前後にログを出力する」というメソッドを作り,呼び出してみましょう。

using UnityEngine;
// Action のため
using System;

public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        // Start → A → End の順にログ出力
        StartEndChecker(((object o) => Debug.Log(o)), "A");
    }

    /// <summary>
    /// 任意の処理の前後にログを出力する
    /// </summary>
    /// <param name="action">任意の処理</param>
    /// <param name="obj">任意の処理の引数</param>
    void StartEndChecker(Action<object> action, object obj)
    {
        Debug.Log("Start");
        action(obj);
        Debug.Log("End");
    }
}

Console ウィンドウに "A" と出力されている画像
Console ウィンドウに出力された値

引数に指定したAという文字が,StartEndの間に出力されています。

ラムダ式で用意したoパラメータには,メソッド呼び出し時の第2引数であるAが割り当てられます。

docs.microsoft.com

それでは,oパラメータを無視してBという値を直接入力するとどうなるでしょう?

// Start() 内のみ書き換え
void Start()
{
    // Start →?→ End の順にログ出力
    StartEndChecker(((object o) => Debug.Log("B")), "A");
}

Console ウィンドウに "B" と出力されている画像
Console ウィンドウに出力された値

Bと出力されました。

つまり,デリゲート内で直接指定した値の方が優先されるという事です。

これでは第2引数の存在意義がなくなってしまいますし,可読性にも問題があります。

そこで,第2引数を省略する方法を2つ御提案いたします。

既定値付きパラメータ(オプション引数)にする

docs.microsoft.com

第2パラメータであるobjに既定値を設定すると,呼び出し時に省略する事が出来ます。

using UnityEngine;
// Action のため
using System;

public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        // Start →?→ End の順にログ出力
        StartEndChecker((object o) => Debug.Log("B"));
    }

    /// <summary>
    /// 任意の処理の前後にログを出力する
    /// </summary>
    /// <param name="action">任意の処理</param>
    /// <param name="obj">任意の処理の引数</param>
    void StartEndChecker(Action<object> action, object obj = default)
    {
        Debug.Log("Start");
        action(obj);
        Debug.Log("End");
    }
}

StartEndChecker()の呼び出し時に第2パラメータであるobjを省略すると,defaultが代入されます。

そこに直接Bを指定し上書きしているため,先程のAのような意味のない引数を書く必要がありません。

パラメータ配列(可変長引数)にする

docs.microsoft.com

第2パラメータであるobjをパラメータ配列にすると,呼び出し時に省略する事が出来ます。

using UnityEngine;
// Action のため
using System;

public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        // Start →?→ End の順にログ出力
        StartEndChecker((object[] objs) => Debug.Log("B"));
    }

    /// <summary>
    /// 任意の処理の前後にログを出力する
    /// </summary>
    /// <param name="action">任意の処理</param>
    /// <param name="objs">任意の処理の引数</param>
    void StartEndChecker(Action<object[]> action, params object[] objects)
    {
        Debug.Log("Start");
        action(objects);
        Debug.Log("End");
    }
}

StartEndChecker()の呼び出し時に第2パラメータであるobjectsを省略すると,長さゼロのobject配列が代入されます。

そこに直接Bを指定し上書きしているため,先程のAのような意味のない引数を書く必要がありません。

ちなみに,呼び出し時の第2引数を適用したい場合は以下のような記法になります。

// Start() 内のみ書き換え
void Start()
{
    // Start → A → End の順にログ出力
    StartEndChecker(((object[] objs) => Debug.Log(objs[0])), "A");
}


終わりに

パラメータが複雑に絡み合うため,正確に理解する事が重要ですね。

以上,型パラメータありデリゲートのパラメータ化についてでした。