++C++; // 未確認飛行 C MVVMパターンを使ったクロス・ターゲット開発 C#たんと学ぶ わりと硬派なソフトウェア開発講座 番外編「Windows Phone 7」

Top総合 目次C# によるプログラミング入門

[雑記] 匿名デリゲートのコンパイル結果

このエントリーをはてなブックマークに追加

目次

キーワード

概要

結局のところ、匿名メソッドは、 コンパイラによるメソッド・クラスの自動生成になります。

匿名メソッドのコンパイル結果

例えば、以下のようなコードは、

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();
  }

[お問い合わせ](q)