C#ではメソッドの中にメソッドを定義して使用することが出来ます。
メソッド内で定義されたメソッドのことをローカル関数といいます。C#7.0からの機能です。
ローカル関数は定義されたメソッド内からのみアクセスすることができます。
また、ローカル関数内から親メソッド(ローカル関数が定義されているメソッド)内のローカル変数にアクセスすることができます。
メソッド内で何度も使いたい処理があるけど他には公開したくないという時にローカル関数が活躍します。他にもそのメソッド内でしか使えないので他の人が誤ってそのメソッドを呼び出すということがなくなります。
他にメソッド内にメソッドを定義して使用する方法としてデリゲート型(匿名メソッド)を使うこともできます。
ローカル関数の使い方
ローカル関数の定義はメソッドの定義とほとんど同じです。
using System;
class Program
{
public static void Main()
{
// ローカル関数の定義
void localFunc1(object o) {
Console.WriteLine(o);
}
// ローカル関数を実行する
localFunc1("ローカル関数[localFunc1]を呼び出す。");
// ローカル関数の定義
// 処理が1行(1つの式)の場合はブロック{ } を省略できる
void localFunc2(object o) => Console.WriteLine(o);
// ローカル関数を実行する
localFunc2("ローカル関数[localFunc2]を呼び出す。");
// ローカル関数の定義(戻り値のあるメソッド)
int localFunc3(int num) {
return num + 100;
}
localFunc2(localFunc3(10));
}
}
出力結果はこんな感じです。
ローカル関数[localFunc1]を呼び出す。
ローカル関数[localFunc2]を呼び出す。
110
親メソッドのローカル変数にアクセスする
ローカル関数は親メソッドのローカル変数にアクセス(取得、変更)することができます。
using System;
class Program
{
public static void Main()
{
// ローカル変数
int value1 = 10;
// ローカル関数の定義
int localFunc1(int num) {
// ローカル変数にアクセス
return value1 + num;
}
// ローカル関数を実行する
Console.WriteLine(localFunc1(20));
// ローカル関数内でローカル変数の値を変更する
int value2 = 100;
void localFunc2() => value2 += 50;
localFunc2();
Console.WriteLine(value2);
}
}
30
150
また、ローカル関数内から同じクラスインスタンスのメンバー(フィールド、メソッド、プロパティなど)を使用することができます。
using System;
class Program
{
public static void Main()
{
var cls = new SampleClass();
cls.SampleMethod();
}
}
class SampleClass {
// フィールド
private int Field = 20;
// メソッド
private void Method() => Console.WriteLine("Methodが実行されました");
// プロパティ
private int Property { get; set; } = 10;
public void SampleMethod() {
// ローカル関数
void f() {
// ローカル関数内からクラスメンバーにアクセス
Console.WriteLine($"Property={this.Property}");
Console.WriteLine($"Field={this.Field}");
this.Method();
}
// ローカル関数を実行
f();
}
}
Property=10
Field=20
Methodが実行されました
静的ローカル関数(static) [C#8.0 から]
ローカル関数にstaticキーワードを付けるとローカル関数内で親メソッドのローカル変数を参照できないようにすることが出来ます。
これにより意図しないローカル変数へのアクセスを制限することができます。
using System;
class Program
{
public static void Main()
{
int number = 10;
static void f() {
// ↓コンパイルエラーになる
// Console.WriteLine(number);
Console.WriteLine("静的ローカル関数です。使用できるのはローカル関数内に変数のみ");
int a = 10;
Console.WriteLine(a);
}
f();
}
}
変数のシャドーイング [C#8.0 から]
C#8になる前までは、ローカル関数の外側(親メソッド)と同じ名前の変数、引数は定義することが出来ませんでした。
C#8.0からはローカル関数内で外側にある同じ名前の変数、引数が定義できるようになりました。「変数のシャドーイング」といいます。
同じ名前の変数、引数でもローカル関数内では別物として扱われます。
using System;
class Program
{
public static void Main()
{
method(10);
}
static void method(int var1) {
string var2 = "test";
// ローカル関数f
void f(int var2) // 引数var2 は 外側のローカル変数var2 とは別もの
{
// 変数var1 は外側の引数var1 とは別もの
int var1 = 100;
Console.WriteLine($"var1={var1}, var2={var2}");
}
f(200);
}
}
var1=100, var2=200
ローカル関数を定義できる場所
ローカル関数はメソッドの他にも以下のブロック内でも定義することが出来ます。
- メソッド
- コンストラクタ
- プロパティ
- ラムダ式
- ローカル関数
using System;
class Program
{
public static void Main()
{
// ラムダ式の中のローカル関数
Action act = () => {
void f(object o) => Console.WriteLine(o);
f("ラムダ式の中のローカル関数の実行");
};
act();
// プロパティ内のローカル関数を呼び出す
var cls = new TestClass();
cls.TestProperty = "";
var p = cls.TestProperty;
// ローカル関数内のローカル関数を呼び出す
void f(object o)
{
void f_inner(object o) => Console.WriteLine(o);
f_inner(o);
}
f("ローカル関数のローカル関数を実行");
}
class TestClass {
// コンストラクタ内のローカル関数
public TestClass() {
void f(object o) => Console.WriteLine(o);
f("コンストラクタ内のローカル関数を実行");
}
// プロパティ内のローカル関数
public string TestProperty {
get {
void f(object o) => Console.WriteLine(o);
f("プロパティget内のローカル関数を実行");
return "";
}
set {
void f(object o) => Console.WriteLine(o);
f("プロパティset内のローカル関数を実行");
}
}
}
}
ラムダ式の中のローカル関数の実行
コンストラクタ内のローカル関数を実行
プロパティset内のローカル関数を実行
プロパティget内のローカル関数を実行
ローカル関数のローカル関数を実行
C# 記事まとめページに戻る(他のサンプルコードもこちら)
コメント