[C#]Action, Func の使い方

この記事は、メソッドを引数で渡したい、できるの? という人に向けた記事です。
知識が VS2005 くらいで止まっており、delegate は知ってるんだけど……という方にも役立つかもしれません。

delegate

はじまりは delegate(デリゲート)という命令でした。

class Class1
{
    delegate void MyMethod(int a, int b);

    public void Caller()
    {
        MyMethod[] method =
        {
            methodA,
            methodB,
        };

        methods[0](5, 4);   // 5 + 4 = 9
        methods[1](5, 4);   // 5 - 4 = 1
    }

    void methodA(int a, int b)
    {
        Debug.WriteLine($"a + b = {a + b}");
    }

    void methodB(int a, int b)
    {
        Debug.WriteLine($"a - b = {a - b}");
    }
}

こんな風にメソッドを変数に入れて使うことを目的とした命令です。
これはこれで便利なのですが、

  • いちいち delegate の宣言をする必要がある
  • しかも、それに名前までつける必要がある

という点がちょっと面倒でした。

Action (or Func) で置き換える

この delegate の宣言をなくせるのが Action や Func の役割です。
先ほどのコードを次のように置き換えることができます。

class Class1
{

    public void Caller()
    {
        Action<int, int>[] methods =
        {
            methodA,
            methodB,
        };
    }

        methods[0](5, 4);   // 5 + 4 = 9
        methods[1](5, 4);   // 5 - 4 = 1
    }

    void methodA(int a, int b)
    {
        Debug.WriteLine($"a + b = {a + b}");
    }

    void methodB(int a, int b)
    {
        Debug.WriteLine($"a - b = {a - b}");
    }
}

3行目の delegate 宣言が消え、6 行目が Action<int, int> に置き換わりました。
Action はこのように、直接 delegate の指示を行うことができます。名前をつける必要もありません。

Action<int, int>

int, int は引数に応じて変化します。今回は int a, int b のメソッドをまとめたため、int, int という宣言になりました。

もし、int a, string b のメソッドをまとめるなら、次のように宣言します。

Action<int ,string>

では、戻り値がある場合はどうでしょう? bool methodA(int a, int string) をまとめる場合は……。

Func<int, string, bool>

と、Action から Func に変更し、最後に戻り値の型を記述します。

このように、どんな型であろうと Action / Func を使うことで渡すことが出来ます。

Action と UnityAction の違いは?

unity には UnityAction と呼ばれる Action と似たような宣言があります。
両者はほぼ同じなのですが、UnityAction のみ、UnityEvent で使える、といった点は覚えておくといいかもしれませんが、正直あまり使い道はないかな……? という気もします。

delegate はもういらない?

個人的にはいらないかなー、と思いますが SE 業務など「古き良き伝統を守る」会社での仕事だと、delegate を強要されるケースはあるかもしれませんね。
Windows.Forms を使ってる場合の定型が delegate と event を使ったイベント記法だったりするので。

なんか、こんなやつ。EventArgs を(必要があれば)自己流カスタムするのがとにかく面倒で嫌いだった……。

class Class1
{
    public class MyEventArgs : EventArgs
    {
        public bool Ready;

        public MyEventArgs(bool ready)
        {
            Ready = ready;
        }
    }
    public delegate void MyClickHandler(object sender, MyEventArgs args);
    public event         MyClickHandler OnMyClick;

    public void Caller()
    {
        OnMyClick += onMyClick;
    }

    void onMyClick(object sender, MyEventArgs args)
    {
        Debug.WriteLine("click!");
    }
}

public event Action OnMyClick; みたいな書き方で正直いいとも思う。古き良き伝統さえなければ……。

このあたりは状況(環境)に応じて、使い分けましょう!

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA