渋谷ほととぎす通信

新しいこと、枯れたこと問わず大庭が興味を持ったものを調査、生活の効率を求める完全趣味の技術ブログ。基礎を大事にしています。

C#のActionとローカル関数のどちらを使うべきか調査


上の記事内で書いたソースにローカルメソッドを使ったのですが、それがどういう動きをするのか、Actionと何が違うのかを本記事では調べます。

ローカル関数はC#7から登場

ローカル関数はその名の通り、関数内に定義でき、その関数内でしか参照できない関数です。C#7から登場なので、Unity使いにとっては比較的最近使えるようにな機能ということになります。

Actionとどう違うのか?

同じような機能はActionでも実装可能です。


恒例のSharpLabで、どのようにIL前のC#にコンパイルされるか調査してみます。


以下が検証コードです。

  • M関数・・・Actionを使用
  • N関数・・・ローカル関数を使用
using System;

public class C 
{
    public void M() 
    {
        Action a =()=>{ Console.WriteLine("hoge"); };
        a();        
    }
    
    public void N()
    {
        void b(){ Console.WriteLine("hoge"); };
        b();
    }
}

コンパイルされたC#はこうなる

全ソースはコチラ

public class C
{
    [Serializable]
    [CompilerGenerated]
    private sealed class <>c
    {
        public static readonly <>c <>9 = new <>c();

        public static Action <>9__0_0;

        internal void <M>b__0_0()
        {
            Console.WriteLine("hoge");
        }
    }

    public void M()
    {
        (<>c.<>9__0_0 ?? (<>c.<>9__0_0 = new Action(<>c.<>9.<M>b__0_0)))();
    }

    public void N()
    {
        <N>g__b|1_0();
    }

    [CompilerGenerated]
    private static void <N>g__b|1_0()
    {
        Console.WriteLine("hoge");
    }
}

中身を見ていきます。

ローカル関数の処理

  1. ローカル関数bをprivate関数として関数Nの外に出す
  2. N関数がb関数を呼ぶ

というシンプルな処理になっています。

Actionの処理

  1. 事前にActionで定義された処理を含むprivate classを定義
  2. private classのstaticなインスタンスを生成しておく
  3. M関数実行初回にActionオブジェクトを生成(2度目以降はprivate classのstatic変数のキャッシュを利用)
  4. private classに定義したActionの処理を実行

ローカル関数と比べると複雑で且つ結構重ための処理をしています。

結論

メモリアロケーション、CPU負荷の観点から、Actionとローカル関数のスワップが可能であれば、ローカル関数を使用すべきという結論に至りました。

個人的に実戦でローカル関数をあまり使用した経験がないので、何かトラブルがあったら、また報告させていただきます。

参考