連載:C# 3.0入門

第1回 ラムダ式

株式会社ピーデー 川俣 晶
2008/04/04

ラムダ式と匿名メソッドの違い

 さて、なぜラムダ式は匿名メソッドよりも短く書けるのだろうか。そんな手品のようなことが本当に可能なのだろうか。何か重要な情報が欠落しているのではないだろうか。その疑問に答えるために、匿名メソッドとラムダ式を比較しながらラムダ式の書き方を見てみよう。

using System;

delegate int SampleDelegate(int x, int y);

class Program
{
  private static void Calculate(int x, int y, SampleDelegate calculator)
  {
    Console.WriteLine(calculator(x, y));
  }

  static void Main(string[] args)
  {
    // 匿名メソッド
    Calculate(1, 2,
      delegate(int x, int y) { return x + y; }); // 出力:3

    // ラムダ式
    Calculate(1, 2, (x, y) => x + y); // 出力:3
  }
}
リスト9 匿名メソッドとラムダ式の比較

 このプログラムの以下の部分がそれぞれ匿名メソッドとラムダ式である。

匿名メソッド
  delegate(int x, int y) { return x + y; }

ラムダ式
  (x, y) => x + y

 この2つを見比べると以下のことが分かるだろう。

  • delegateキーワードが消えた
  • returnキーワードが消えた
  • 引数の型指定(int)が消えた
  • 中カッコ({、})が消えた
  • 文末のセミコロン(;)が消えた
  • 「=>」の2文字が増えた

 以下、これらを1つ1つ検証していこう。

 まず、ラムダ式で使用されている「=>」は「=>演算子」と呼ばれ、「〜に入力」と読む。上記の場合、「x、yをx + yに入力」と読む(とはいえ、無理にそう読む必要はない。筆者はいちいち「〜に入力」とは読んでいない)。

 delegateキーワードは単に消えたのではなく、=>演算子に置き換えられたと考えると分かりやすいだろう。これらはそれぞれ、「匿名メソッドである」「ラムダ式である」という意図を示す重要な記述である。これによって、delegateの8文字が「=>」の2文字に減って6文字減である。

 次のreturnキーワードだが、ラムダ式はそれ自身が「式」であるため、returnは必要ない(ステートメント・ブロックとして記述する場合はreturn文が必要になる。詳しくは後述)。例えば、

int method() { return 1 + 2; }

にreturnは必要だが、式である、

1 + 2

にreturnは必要ないのと同じである。これでreturnの6文字が減った。

 引数の型指定がないことは、型の厳密なチェックがおろそかになると心配する人や、面倒な型宣言がなくなってアバウトに書けるようになると喜んだ人もいるかもしれないが、どちらもハズレである。リスト9では、Calculateメソッドの引数はSampleDelegateという型であり、SampleDelegateデリゲートの引数はint型が2つと宣言されているので、いちいちラムダ式で宣言しなくとも、xとyはそれぞれint型に確定する。

 念のために補足すると、これはラムダ式固有のものではない。匿名メソッドでは確かに引数は明示的に型を添えて示す必要があったが、戻り値の型に関しては同様の手段により推測されていた。逆にいえば、そのような推測ができない状況では、匿名メソッドもラムダ式も使用できない。型が確定しないアバウトな状態では使えない、ということである。

 次に中カッコが消えた理由と、文末のセミコロンが消えた理由は、returnが消えた理由と同じで、ラムダ式はそれ自身が「式」だからである(逆に、中カッコを付ければラムダ式も「ステートメント型のラムダ」として文を記述できる。詳しくは後述)。

 以上である。タネも仕掛けもなく、厳密さを損なうこともなく、圧倒的な構文の短さを実現している。

ステートメント型のラムダ

 ここまで見てきたラムダ式は、「式形式のラムダ」と呼ばれる。まさに「式」によって内容が記述されるからである。

 一方、内容を文の列として記述する「ステートメント型のラムダ」も存在する。簡単な式ではなく、込み入ったコードを書く場合はこちらの方が便利である。書き方は簡単で、式の代わりに中カッコで囲った文の列を書くだけである。

 以下に、一例を示す。

using System;

class Program
{
  static void Main(string[] args)
  {
    // ステートメント型のラムダ
    Action<string> method = (filename) =>
      {
        if (filename == null)
          Console.WriteLine("Hello!");
        else
          System.IO.File.WriteAllText(filename, "Hello!");
      };

    method(null); // 出力:Hello!
    method("hello.txt"); // hello.txtファイルを作成
  }
}
リスト10 ステートメント型のラムダの例

 ステートメント型のラムダが値を返す場合はreturn文を使用する。例えば、以下をステートメント型に変更する場合はこのように修正する。

式形式のラムダ
  (n) => a == n;

ステートメント型のラムダ
  (n) => { return a == n; };

 これを見ると分かるとおり、かなり文字数が増えて冗長な感じになる。しかし、式形式のラムダでは書けず、ステートメント型のラムダが要求されるケースでは、かなり長めのコードを書くことになるため、returnキーワードが増える程度のオーバーヘッドはさほど気にはならない。


 INDEX
  C# 3.0入門
  第1回 ラムダ式
    1.C# 3.0とは何か?/C# 3.0の適用範囲
    2.ラムダ式は何をもたらすか
  3.ラムダ式と匿名メソッドの違い/ステートメント型のラムダ
    4.式形式のラムダの可能性/型指定の省略/何もしないラムダ式
    5.ラムダ式の使用例/ラムダ式のさまざまなバリエーション
 
インデックス・ページヘ  「C# 3.0入門」


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 記事ランキング

本日 月間