【C#】ローカル関数(Local Functions)でヘルパーメソッドをスコープ内に隠蔽する

C# 7.0 で導入された「ローカル関数」を使用すると、メソッドの内部に、そのメソッド専用の関数を定義することができます。

従来、特定のメソッドからしか呼ばれない小さなヘルパーメソッドであっても、クラスの private メソッドとして定義する必要があり、クラス全体の可読性を下げる要因となっていました。ローカル関数を利用することで、**「その処理を使う場所の直近」**にロジックを配置でき、カプセル化の促進とコードの見通しを良くすることが可能です。

本記事では、文字列配列をスネークケースに変換する処理を例に、ローカル関数の定義と利用方法を解説します。

目次

実装例:スネークケース変換処理

以下のコードは、パスカルケース(PascalCase)で書かれた単語のリストを、スネークケース(snake_case)に変換して出力するプログラムです。変換ロジックである ToSnakeCase 関数は Main メソッドの内部でのみ使用されるため、ローカル関数として定義しています。

using System;
using System.Linq;

namespace LocalFunctionExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // 変換対象の文字列配列
            var words = new[]
            {
                "StringBuilder",
                "ToSnakeCase",
                "IsLetter",
                "ToLower"
            };

            Console.WriteLine("--- 変換結果 ---");

            foreach (var word in words)
            {
                // ローカル関数を呼び出し
                var snakeCase = ToSnakeCase(word);
                Console.WriteLine($"{word} -> {snakeCase}");
            }

            // --- ここにローカル関数を定義 ---
            
            // パスカルケースをスネークケースに変換するローカル関数
            // この関数は Main メソッドの外からは見えない
            string ToSnakeCase(string value)
            {
                if (string.IsNullOrEmpty(value)) return value;

                // 2文字目以降の大文字の前に "_" を挿入する処理
                var convertedSequence = value.Select((c, i) => 
                    (i > 0 && char.IsUpper(c)) ? "_" + c : c.ToString()
                );

                // 文字列を結合して小文字化
                return string.Concat(convertedSequence).ToLower();
            }
        }
    }
}

ローカル関数の特徴とメリット

1. スコープの限定(汚染防止)

ローカル関数は定義されたメソッド(親メソッド)の内部からしか呼び出せません。これにより、「このメソッドはどこから使われているのか?」とクラス全体を探し回る必要がなくなり、コードの依存関係が明確になります。

2. 親メソッドの変数へのアクセス(クロージャ)

ローカル関数は、親メソッドで定義された変数や引数に直接アクセス(キャプチャ)することができます。これにより、引数としてわざわざ値を渡す手間を省くことができます。

void ProcessData(int threshold)
{
    var numbers = new[] { 1, 5, 10, 2 };
    
    // 親メソッドの引数 threshold を直接使用できる
    var filtered = numbers.Where(IsOverThreshold);
    
    bool IsOverThreshold(int n) => n > threshold;
}

3. イテレータや非同期メソッドでの例外処理の即時化

yield return を使うイテレータメソッドや async/await メソッドでは、引数の検証(nullチェックなど)を即座に行い、実処理をローカル関数に委譲するパターンがよく使われます。これにより、遅延実行される処理の前に確実にエラーを検出できます。

まとめ

ローカル関数は、コードの凝集度を高めるための強力な機能です。

  • 使用場所: ヘルパーメソッドが特定のメソッドからしか参照されない場合。
  • 記述位置: 親メソッド内の任意の位置(一般的にはメソッドの末尾、または使用する直前)。
  • 効果: クラスレベルの名前空間を汚さず、ロジックを整理できる。

単なるコードの整理だけでなく、変数のキャプチャなどの機能も活用し、意図が伝わりやすいコード記述に役立ててください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次