ローカル関数(local function)を理解しよう!

[C#] ローカル関数(local function)を理解しよう!

※ 当サイトは広告を含みます。

ここではC#のローカル関数を学習します。
当たり前ですが、関数の知識が必要になります。

ローカル関数(local function)

これはメソッドの中に関数(メソッド)を記述することです。
より正確にはコンストラクタとかプロパティの内部にも記述できます。

管理人
管理人

C#には厳密な意味で関数は無いといったが、あれは嘘だ!

りさ
りさ

はっ?

管理人
管理人

いや、ローカル関数が正式名称って知らなかった。

正直、特に難しい部分はなく普通にメソッドの中に関数を書けばOK。


namespace Sample
{
  internal class Program
  {
    internal class Calculator
    {
      internal void Display()
      {
        // ローカル関数を定義する
        int _sum(int a, int b)
        {
          return a + b;
        }

        // ローカル関数を呼び出す
        var total = _sum(16, 32);

        Console.WriteLine($"total={total}");
      }
    }

    static void Main(string[] args)
    {
      var calculator = new Calculator();
      calculator.Display();
    }
  }
}
管理人
管理人

勝手にローカルメソッドとかインナーメソッドと呼ぶと思ってたけど違うらしい。

りさ
りさ

これ何のメリットがあるんですか?

管理人
管理人

有効範囲が超狭い。ローカル関数はクラス内に限定するprivateよりも強力な隠蔽になる。

補足正確には定義した{}(ブロック)内で利用することができます。

記述時の制約

普通のメソッドと違って記述できないこともあります。

例えばアクセス修飾子です。ローカル関数はアクセス修飾子を付けることに意味がないので記述できません。
ただ、何が駄目を覚える必要はありません。普通に書きたいように書いて駄目なら記述不可です。

シャドーイング

先に次のサンプルコードを見てみましょう。


namespace Sample
{
  internal class Program
  {
    internal class Calculator
    {
      internal void Display(int a, int b) // 同名の引数名
      {
        // ローカル関数を定義する
        int _sum(int a, int b) // 同名の引数名
        {
          return a + b;
        }

        // ローカル関数を呼び出す
        var total = _sum(a, b);

        Console.WriteLine($"total={total}");
      }
    }

    static void Main(string[] args)
    {
      var calculator = new Calculator();
      calculator.Display(2, 8);
    }
  }
}

実はこれ、C#的には不思議な記述です。ポイントは上位のメソッドとローカル関数の引数名です。
メソッドも1つのブロックなので、本来であれば変数名が被るとビルドエラーになります。

しかし、上記はビルドエラーになりません。この機能をシャドーイングと呼びます。
シャドーイングとは、メソッドの内外に存在する同名変数を別物として扱う機能です。

ちなみにシャドーイングが導入されたのはC#8.0です。つまり、それ以下の環境ではビルドエラーになります。
このC#8.0とは、ほぼほぼ.Net以降の話です。そのため、.Net Frameworkではシャドーイングは機能しません。

便利な使い道

先程の隠蔽は1つの例です。個人的にはメソッド内で処理を繰り返す場合に使います。
後は多重ループとかエラー処理とか、いい感じにreturnを活用できる場合に便利です。


namespace Sample
{
  internal class Program
  {
    internal class Calculator
    {
      internal void Process(int n)
      {
        // 複数回実行したい処理
        bool _process()
        {
          var r = new System.Random();

          if (r.Next(0, 5) != 0) // 適当に成否判定
            return false; // 失敗

          return true; // 成功
        }

        // 実処理
        for (var i = 0; i < n; i++)
        {
          var result = _process();
          if (result)
          {
            Console.WriteLine($"成功");
            break;
          }

          Console.WriteLine($"{i + 1}回目の失敗");
        }
      }
    }

    static void Main(string[] args)
    {
      var calculator = new Calculator();
      calculator.Process(10);
    }
  }
}
管理人
管理人

こんな感じに書けばリトライ処理も簡単に書ける。

あとがき

クラスに属してることに変わりないし、名前ローカルメソッドで良くね?

◆ C#に関する学習コンテンツ

この記事は参考になりましたか?

関連記事

コメント

この記事へのコメントはありません。