匿名メソッド
匿名メソッドは、名前なしのメソッドである。
C# 1.1以前ではデリゲートを利用する場合、必ず名前付きのメソッドが必要だったが、これを省略できるようにしたものである。
(デリゲートはCでいうところの関数ポインタ型と考えればよいのかな?)
イベントハンドラとしての利用価値が高そうに感じる。
対象バージョン
C# 2.0以降
例1 デリゲートから宣言
全く実用的なサンプルではないですが、2つのint型を足し算するものである。
//デリゲートの宣言 delegate int Plus(int intA, int intB); //匿名メソッドの実装 //ちなみに、パラメータが不要の場合、(int intA, int intB)は省略できる。 Plus plus_a_and_b = delegate (int intA, int intB) { return intA + intB; }; // ; は必須 //匿名メソッドの実行 int int_c = plus_a_and_b(1, 3);
例2 既存の汎用デリゲートを利用する場合。
.NET Framework 2.0以降には Action、Predicate、MethodInvokerなどを利用すると、デリゲートの宣言が不要となる。
// Actionデリゲートを利用した匿名メソッド実装 Action<int> act = delegate(int param) { ... }; // 匿名メソッドの利用 act(10);
例3 イベントハンドラとして利用する場合。
チェックボックスなどのClickイベントのイベントハンドラに匿名メソッドを使用する場合など利用できる。この場合、Clickはすでに定義されているので、実装するだけである。チェックボックスのClickイベントはEventHandlerデリゲートである。パラメータは (object sender,EventArgs e) であるが、使用しない場合は、次のように省略できる。
checkBox1.Clicked += delegate {
....
};
Clickedイベントが発生するたびに、上記のコードが実行される。
スコープ
匿名メソッドのパラメータは当然ながら実装内部でのみ利用可能である。外部からは利用できない。
Action<int> method1 = delegate (int param) { }; param = 1; // <--- これはNG
これに対し、外側で宣言した変数など、実装部分でアクセスできるものは利用可能である。
int local_var = 0; Action<int> method1 = delegate (int param) { local_var = param; }; ... method1(3); // <--- この結果、local_varには3が入る。
注意1 実装する箇所
Webで次のような感じの例を見た。もちろん、そのページでもこの解釈は間違っていると説明している。
delegate int SampleDeligate(void); DSampleDeligate[] method_list = new SampleDeligate[10]; ... for (int i = 0; i < 10; i++ ) { // 匿名メソッドの実装 method_list[i] = delegate { return i; } } for (int j = 0; j < 10; j++ ) { // 匿名メソッドの実行 Console.Write("{0} ", method_list[j]()); }
この結果は、次の下段のようになる。
0 1 2 3 4 5 6 7 8 9 // 期待したもの 10 10 10 10 10 10 10 10 10 10 // 実際の動作
匿名メソッドの実装はあくまで実装であり、コードが実行されるわけではないことに注意が必要である。上記例では実際に実行される箇所ではiは既に10になっているので、下段のような結果となる。
注意2 スコープ
前述したように、匿名メソッドで利用できる変数などは、匿名メソッドの実装箇所でアクセスできるものである。これは、実行する箇所でアクセスできるものではないので注意が必要である。
「注意1」の例で2つめのループ変数「j」を「i」に変えてみるとよくわかる。結果は、「注意1」と同じとなる。1回目と2回目で同じループ変数名となるが、匿名メソッドが参照するのはあくまでも実装していたときにアクセスしていた変数「i」である。