C# ゼロから理解するラムダ式:C#でラムダ式を書く方法 #9

前回までに「デリゲート」と「匿名メソッド」を解説してきました。ここまでくればラムダ式を理解できㇽので解説していきます。ラムダ式は「ラムダ演算子」を使って式を単純にして記述できる記法になります。

演算子ですので基本的には「式」を記述していくのが「ラムダ演算子」です。また、ラムダ演算子を使用した式が「ラムダ式」と呼ばれています。

ラムダ演算子の特徴

ラムダ式で使用するラムダ演算子にはいくつかの特徴があります。

  • ラムダ演算子は「=>」で記述する
  • ラムダ演算子は「goes to」と読む
  • 左辺がパラメータであり、右辺が式である

基本的に大した特徴ではありませんが、覚えておくことに越したことはありませんので、なんとなく「聞いたことあるな」くらいで知っておいてもらえたらと思います。

(パラメータ) => (式);

記述方法はこれから解説していくので、徐々に覚えてもらえれば良いでしょう。

delegateとラムダ式の違い

これまで学んできたデリゲートとラムダ式がどう違うかについて紹介します。以下のサンプルコードを見てみてください。以下の式は同じ処理内容ですが記述方法を変えています。

//匿名メソッド
delegate (string s){ return s.Length == 3; }

//ラムダ式
(s) => s.Length == 3

上記は匿名メソッドとラムダ式の違いです。ラムダ式のほうが圧倒的に文字数が少なくなっていますね。このサンプルは戻り値を持つものですが、詳しいことはおいておくとして、ラムダ式のイメージだけ湧けば十分です。

では、新規のアプリケーションを作成して以下のサンプルコードを書いてみてください。実際に動かして、どのように処理がされるかを確認してみましょう。

using System;

namespace App06
{
    class Program
    {
        //デリゲートの宣言
        delegate void Output(string str);

        //デリゲートの処理部分
        static private void Write(string input)
        {
            Console.WriteLine(input);
        }

        //デリゲートを使用する箇所
        static private void WriteLogin(Output process, string input)
        {
            process(input);
        }

        //メイン処理
        static void Main(string[] args)
        {
            Console.WriteLine("ログイン名を入力してください。");
            var input = Console.ReadLine();

            //デリゲート
            WriteLogin(Write, input);

            //匿名メソッド
            WriteLogin(delegate (string s)
            {
                Console.WriteLine(s);
            },
            input);

            //ラムダ式
            WriteLogin(
                (s) => Console.WriteLine(s),
                input);

            Console.ReadLine();
        }
    }
}

特に注目するべきはメイン処理部分の以下の記述になります。デリゲート、匿名メソッド、ラムダ式の3つをすべて書いてみました。

//デリゲート
WriteLogin(Write, input);

//匿名メソッド
WriteLogin(delegate (string s)
{
    Console.WriteLine(s); 
},
input);

//ラムダ式
WriteLogin(
    (s) => Console.WriteLine(s),
    input);

上記からわかる通りラムダ式であっても、デリゲートでも同じ処理を記述することが可能です。記述量で比べてみるとデリゲート > 匿名メソッド > ラムダ式になるかなと思います。

C#でラムダ式を書く方法

デリゲートとラムダ式を比べて、ラムダ式がどのように記述されるのかを書いてみました。次はラムダ式の書き方にも色々とある、という点を紹介していきたいと思います。

ラムダ式の引数の書き方

ラムダ式では引数を受け取ることができます。まずはラムダ式における引数の特徴から以下で紹介したいと思います。

  • 引数の型を記述する必要がない
  • 引数がない場合はカッコは省略できない
  • 引数が一つだけの場合は括弧を省略できる
  • 引数が複数の場合も括弧を省略できない
  • 戻り値がある場合はreturnを書く必要がない

簡単なサンプルソースは以下の通りになります。また、参考までに匿名メソッドも記述していますので比較してみてください。

//匿名メソッド
delegate (string s) { return s.Length == 3; }

//引数なしの場合
() => Console.WriteLine("通知されたよ!");

//引数1つの場合
s => s.Length == 3;

//複数の引数の場合
(s, len) => s.Length == len;

ラムダ式では引数の型を記述する必要がありません。これはC#が持つ「型推論」の機能によって、変数の型をプログラムが判断してくれるからです。引数の型を記述する必要がないため、ラムダ式のほうがよりシンプルに記述できます。

それでは実際のコードを書いていきましょう。新規のコンソールアプリケーションを作成して以下を試してみてください。

using System;

namespace App07
{
    class Program
    {
        //デリゲートの宣言
        delegate bool CheckMethod(int num);

        //デリゲートの実行部分
        static void WriteMessage(CheckMethod method, int num)
        {
            if(method(num))
            {
                Console.WriteLine("10以上の数です。");
            }
            else
            {
                Console.WriteLine("10未満の数です。");
            }
        }

        //メイン処理
        static void Main(string[] args)
        {
            //※数値以外を入力すると例外になるので注意!!
            Console.WriteLine("数値を入力してください。");
            int input = Convert.ToInt32(Console.ReadLine());

            //デリゲートの呼び出し部分
            WriteMessage((n) => n >= 10, input);
            Console.ReadLine();
        }
    }
}

これまでに散々デリゲートなどは解説してきましたので、ここではラムダ式の部分だけを解説したいと思います。ラムダ式の部分は以下の箇所になります。

//デリゲートの呼び出し部分
WriteMessage((n) => n >= 10, input);

引数nを受け取って「nが10以上だったらtrue」を返すようにしています。ラムダ式ではC#の暗黙の型変換を利用するため引数の型を記述する必要はありません。

ラムダ式の色々な記述方法

ラムダ式の引数については前章で解説したので、ここではラムダ式自体の記述方法を解説していきます。ラムダ式には単行で記述する方法だけでなく、複数行にわたって記述する方法もあります。

//左辺がシンプルな式
s => s.Length == 5

//左辺が処理の場合(リターンやセミコロンが必要)
(a, len) =>
{
    if(a[0] == "E")
    {
        return a.Length > len;
    }
    return false;
}

シンプルな式の場合は「(引数) => (式)」で記述できますが、複数行で記述する際は「(引数) => { (式) }」で記述します。そうすることで複雑な処理も記述することができるので覚えておいてください。

ではサンプルを書いていきますので、新規のコンソールアプリケーションを作成して以下のコードを記述してみてください。

using System;

namespace App08
{
    class Program
    {
        //デリゲートの宣言部分
        delegate double DiscountMethod(double input);

        //実行メソッド
        static private void Execute(DiscountMethod method, double input)
        {
            double resultNum = method(input);
            Console.WriteLine($"入力された値は{ resultNum }になりました。");
        }

        //メイン処理
        static void Main(string[] args)
        {
            //数値以外を入力するとエラーになるので注意!!
            Console.WriteLine("数値を入力してください。");
            double input = Convert.ToDouble(Console.ReadLine());

            Execute((n) =>
            {
                if(n >= 10000)
                {
                    //nが10,000以上だったら5%割引する
                    return n * 0.95;
                }
                else
                {
                    return n;
                }
            },
            input);
            Console.ReadLine();
        }
    }
}

上記のアプリケーションにおけるラムダ式の記述部分は以下になります。

Execute((n) =>
{
    if(n >= 10000)
    {
        //nが10,000以上だったら5%割引する
        return n * 0.95;
    }
    else
    {
        return n;
    }
},
input);

Executeメソッドの第一引数である「DiscountMethod」はdoubleを受け取ってdoubleを返す処理をしています。10,000円以上の買い物で5%オフにする処理のような感じです。本らなら端数の出ないint型にするべきですが、ここでは省略しています。

このようにラムダ式を複数行にわたって記述する場合は、「=>」以降を「{ (処理内容) }」とすれば問題なくなります。このようにすれば複雑な処理も記述できるので、必要に応じて使い分けるようにすればラムダ式をマスターしたといっても過言ではありません。