英語では Local Functions と呼び、C# 7.0 から導入された機能です。
これまでメソッドの呼び出しについて学びました。メソッド内のコードブロックから、別のメソッドを呼び出すことが可能で、ルールは以下の通りです。
- 同一クラス内のメソッド:メソッド名に引数を渡すだけで直接呼び出し可能。
- 別クラスのメソッド:対象クラスのインスタンスを生成する必要があり、呼び出すメソッドには
publicを付記しなければなりません。
C# 7.0 より、一つのメソッド内部に独立した関数を定義できるようになりました。これをローカル関数と呼びます。
- スコープの閉じ込め:外側のメソッド内部からのみ呼び出せ、外部コードからはアクセスできない。
- メリット:関連する処理をまとめられ、可読性・保守性が向上する。
- 宣言ルール:ローカル変数とは異なり、ローカル関数は外側メソッド内の任意の場所に定義でき、事前宣言を必要としない。
ローカル関数は外側メソッドのローカル変数をキャプチャできますが、スコープは自身を包含するメソッド内に限定されます。
まず事前知識を補足します。
関数内のローカル変数は上から下へ順次実行されます。変数を使用するには先に宣言する必要があり、順番を逆にすることはできません。
下記コードを例にします。hour は後で定義されているため、宣言前に参照することはできません。
int GetHours()
{
Console.WriteLine(hour);
int hour = DateTime.Now.Hour;
return hour;
}Code language: C# (cs)
hour のスコープがメソッド全体に及んでいたとしても、宣言前に使用することは許可されません。

赤い波線のエラーが表示され、エラーメッセージは上図の通りです。
これは通常のメソッドとは事情が異なります。下側に定義したメソッドを上側から呼び出せるのは、クラスメソッドがクラスのメンバーとして Method Table(メソッドテーブル)に登録され、実行時にテーブルを参照して呼び出し先を解決するためで、上から下へ逐次実行されるわけではないからです。

次のコードでは上部の Main から後述の GetHours を呼んでいます。この動作はローカル変数の宣言ルールとは異なります。
class Program
{
static void Main()
{
Program program = new Program();
program.GetHours();
}
int GetHours()
{
int hour = DateTime.Now.Hour;
return hour;
}
}Code language: C# (cs)
話をローカル関数に戻します。
実例を見てみましょう。
class Program
{
static void Main()
{
Program program = new Program();
program.ZoomIn();
}
public void ZoomIn()
{
// ローカル関数の定義前から呼び出すことが可能
int results0 = ZoomIn5(10);
Console.WriteLine($"A: {results0}");
// ローカル関数:引数 val を5倍にして返す
int ZoomIn5(int val)
{
return val * 5;
}
// ローカル関数を呼び出し
int results = ZoomIn5(10);
Console.WriteLine($"B: {results}");
int results2 = ZoomIn5(5);
Console.WriteLine($"C: {results2}");
}
}
Code language: C# (cs)
ローカル関数のスコープは包含元のメソッド内に限定され、関数定義より前後どちらの位置からでも呼び出せます。
さらに、ローカル関数の名前を外側のメソッドと同名にすることもできます。
class Program
{
static void Main()
{
Program program = new Program();
program.ZoomIn5();
}
public void ZoomIn5()
{
// ローカル関数の定義前から呼び出すことが可能
int results0 = ZoomIn5(10);
Console.WriteLine($"A: {results0}");
// ローカル関数:引数 val を5倍にして返す
int ZoomIn5(int val)
{
return val * 5;
}
// ローカル関数を呼び出し
int results = ZoomIn5(10);
Console.WriteLine($"B: {results}");
int results2 = ZoomIn5(5);
Console.WriteLine($"C: {results2}");
}
}
Code language: C# (cs)
上記コードでは外側メソッドと内部ローカル関数がどちらも ZoomIn5 です。スコープが分かれているため名称衝突は発生しませんが、この書き方は推奨されません。
ローカル関数