結局のところ、匿名メソッドは、 コンパイラによるメソッド・クラスの自動生成になります。
例えば、以下のようなコードは、
class Program { static void Main(string[] args) { // 1. 匿名メソッド Func<int> f1 = delegate() { return 0; }; f1(); } }
以下のコードと同じ意味になります。
class Program { static int AnonymousMethod1() { return 0; } static void Main(string[] args) { Func<int> f1 = AnonymousMethod1; f1(); } }
AnonymousMethod1 の部分は、 実際には <Main>b__0 とかいうような、 C# では通常記述できないような特殊な名前になっていて、 プログラマが明示的に参照することはできません。
匿名メソッド内で、クラスのメンバー変数を参照するような場合には、 インスタンスメソッド(非 static なメソッド)が自動生成されます。
class Program { int member = 0; void Method() { // 2. メンバー変数を参照する匿名メソッド Func<int> f2 = delegate() { return this.member; }; f2(); } }
↓
class Program { int AnonymousMethod2() { return this.member; } int member = 0; void Method() { Func<int> f2 = AnonymousMethod2; f2(); } }
ローカル変数を参照するような匿名メソッドを書いた場合、 以下のように、クラスまで自動生成されます。
class Program { static void Main(string[] args) { // 3. ローカル変数を参照する匿名メソッド int x = 0; Func<int> f3 = delegate() { return ++x; }; f3(); Console.Write(x); } }
↓
class Program { class AnonymousClass { public int x; public int AnonymousMethod() { return ++this.x; } } static void Main(string[] args) { AnonymousClass temp = new AnonymousClass(); temp.x = 0; Func<int> f3 = temp.AnonymousMethod; f3(); Console.Write(temp.x); } }
ローカル変数の変わりに、自動生成されたクラスのメンバー変数アクセスになっています。
この原理が分かれば、以下のプログラムの実行結果で 1 が表示される理由も分かると思います。
class Program { static void Main(string[] args) { int x = 0; Action f = delegate() { Console.Write(x); }; x = 1; f(); } }
このプログラムは以下のように解釈されます。
class Program { class AnonymousClass { public int x; public void AnonymousMethod() { Console.Write(this.x); } } static void Main(string[] args) { AnonymousClass temp = new AnonymousClass(); temp.x = 0; Action f = temp.AnonymousMethod; temp.x = 1; f(); }