連載:[完全版]究極のC#プログラミング

Chapter6 ラムダ式(前編)

川俣 晶
2009/10/19

6.7 デリゲートインスタンスの等価性

 デリゲートのインスタンスは、それ自体が一種の値なので、==演算子やEqualsメソッドなどで容易に同じであるかを調べられる。その際、ラムダ式には興味深い特徴が見られるので解説しておこう。

 まず、別個のコードで生成されたデリゲートは、シグネチャや内容が同じでもイコールとは見なされないことを確認しよう(リスト6.10参照)。

using System;

class Program
{
  static void Main(string[] args)
  {
    Action<int> m1 = (dummy) => { };
    Action<int> m2 = (dummy) => { };

    Console.WriteLine(m1 == m2); //出力:False
  }
}
リスト6.10 別個のコードで生成されたデリゲートの比較

 では、1つのデリゲート生成コードから生成されたデリゲートのインスタンスはイコールと見なされるのだろうか?(リスト6.11参照)

using System;

class Program
{
  static void Main(string[] args)
  {
    Action<int>[] methods = new Action<int>[2];

    for (int i = 0; i < 2; i++)
    {
      methods[i] = (dummy) => { };
    }
      Console.WriteLine(methods[0] == methods[1]); // 出力:True
  }
}
リスト6.11 1つのデリゲート生成コードで2つのデリゲートを作る

 このようにイコールと見なされた。

 だが、ここで安心してはいけない。なぜなら、同じコードから生成されたデリゲートがイコールと見なされないことがあるからだ(リスト6.12参照)。

using System;

class Program
{
  static void Main(string[] args)
  {
    Action<int>[] methods = new Action<int>[2];

    for (int i = 0; i < 2; i++)
    {
      int j = i;
      methods[i] = (dummy) => { j++; };
    }
    Console.WriteLine(methods[0] == methods[1]); // 出力:False
  }
}
リスト6.12 イコールと見なされないデリゲートの例

 ここで追加したのは、変数jである。変数jはループを1回繰り返すごとに新しく誕生する。そして、ラムダ式は変数jを使用しているので、この変数jはキャプチャされる。実は、キャプチャされている変数が同じでなければ、デリゲートはイコールと見なされないのである。このケースでは、methods[0]がキャプチャしている変数jとmethods[1]がキャプチャしている変数jは別物なので、イコールとは見なされないのである。

 逆に、「j++;」を「i++;」に書き換えると、結果はTrueに変わり、イコールと見なされる。この場合、2つのラムダ式がキャプチャしている変数iは同じものであるからだ。

 このような仕様は、イコールの判定が、デリゲートを呼び出して同じ結果を出すか否かの判定に使用できることを意味する。キャプチャした変数が別物であれば、もちろん呼び出して同じ結果になるかどうかはわからない。しかし、同じ変数をキャプチャしていれば、同じ結果になると予測できるわけである。


 INDEX
  [完全版]究極のC#プログラミング
  Chapter6 ラムダ式(前編)
    1.6.1 おかずでもデザートでもなく“ご飯”
    2.6.2 ラムダ式とは何か?/【C#olumn】定義済みデリゲートを活用しよう
    3.6.3 ラムダ式は上位スコープにアクセスできる
    4.6.4 キャプチャされる変数
    5.6.5 注意を要するキャプチャの本質
    6.6.6 デリゲートの共変性と反変性
  7.6.7 デリゲートインスタンスの等価性
    8.6.8 ラムダ式で継承を置き換えてみる
    9.6.9 C# 2.0と匿名メソッド/【Exercise】練習問題
 
インデックス・ページヘ  「[完全版]究極のC#プログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間