C#

【C#】匿名メソッドとラムダ式の基本

デリゲートはメソッドを変数に登録する仕組みです。【C#】デリゲートの基本 では、宣言時にメソッド名を引数として初期化することでメソッドを登録しました。これに対して、匿名メソッドやラムダ式は直接メソッドブロックを記述します。

匿名メソッド

メソッド名を定義せず、デリゲート型の変数に直接メソッドブロックを記述するのが匿名メソッドです。メソッド名がないので匿名メソッドと呼ばれます。

匿名メソッドの定義

匿名メソッドの構文は以下のようになります。

delegate(引数リスト){
            デリゲート変数に登録する処理
        }

戻り値がある場合には、return文が必要になります。引数リストがない場合には(引数リスト)は省略できます。だた匿名メソッドは単体で使うのではなく基本的にはデリゲートに登録して使います。

これだけではよくわからないので、この構文を使った例を見てみましょう。

コード

using System;

internal class Program
{
    delegate void TestDel();

    static void Main(string[] args)
    {
        TestDel delVar = delegate{
            Console.WriteLine("匿名メソッドが呼び出されました");
        };

        delVar();
    }
}

出力結果

匿名メソッドが呼び出されました

上記コードは、引数のない匿名メソッドを利用した例です。9-11行目でデリゲート変数delVarに匿名メソッドが登録されています。11行目の最後の;を忘れないようにしましょう。

次に引数リストのある例も見てみましょう。

コード

using System;

internal class Program
{
    delegate int TestDel(int x, int y);

    static void Main(string[] args)
    {
        TestDel delVar = delegate (int a, int b)
        {
            Console.WriteLine("匿名メソッドが呼び出されました");
            return a + b;
        };

        int ans = delVar(2, 3);
        Console.WriteLine("ans:{0}", ans);
    }
}

出力結果

匿名メソッドが呼び出されました
ans:5

上記コードでは、int型の引数が2つで、int型の戻り値がある匿名メソッドの例です。ここでは匿名メソッドの処理は2行となっていますが、複数行の処理もこの例のように書くことができます。

ラムダ式の基本

ラムダ式は匿名メソッドをより簡略化した方法で記述できます。匿名メソッドは、すべてラムダ式に置き換えることができます。ラムダ式は徹底的に簡略化されていますが、その分最初はわかりにくく感じる部分もあるかもしれません。

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

まずは匿名メソッドとラムダ式の違いを見てみましょう。ラムダ式も基本的にはデリゲートに登録して使います。

コード

using System;

internal class Program
{
    delegate int TestDel(int x, int y);

    static void Main(string[] args)
    {
        //匿名メソッド
        TestDel delVar1 = delegate (int a, int b)
        {
            Console.WriteLine("匿名メソッドが呼び出されました");
            return a + b;
        };

        //ラムダ式
        TestDel delVar2 = (int a, int b) =>
        {
            Console.WriteLine("ラムダ式が呼び出されました");
            return a + b; 
        };

        int ans1 = delVar1(2, 3);
        int ans2 = delVar2(2, 3);
        Console.WriteLine("ans1:{0}, ans2:{1}", ans1,ans2);
    }
}

出力結果

匿名メソッドが呼び出されました
ラムダ式が呼び出されました
ans1:5, ans2:5

上記コードの10-14行目では匿名メソッドでdelVar1を定義していますが、これは17~21行目のラムダ式で定義されたdelVar2と全く同じメソッドです。ラムダ式の構文では、

(引数リスト) => {デリゲート変数に登録する処理}

のようにメソッドを定義できます。=>をラムダ演算子と呼びます。デリゲート変数に登録する処理を、{}を使って複数行のステートメントで表されるとき、これを「ステートメント形式のラムダ」と言います。

ここまで、匿名メソッドと同じ手間のように思われますが、ラムダ式にはいろいろ省けるものがあります。省略できる部分を見ていきましょう。

引数の型を省略できる

ラムダ式では引数の型を省略することができます。例を見てみましょう。

コード

using System;

internal class Program
{
    delegate int TestDel(int x, int y);

    static void Main(string[] args)
    {
        //ラムダ式
        TestDel delVar = (a, b) =>
        {
            Console.WriteLine("ラムダ式が呼び出されました");
            return a + b;
        };

        int ans = delVar(2, 3);
        Console.WriteLine("ans:{0}", ans);
    }
}

出力結果

ラムダ式が呼び出されました
ans:5

上記コードでは引数リストの型を省いて(a, b)と記述しています。型を明示しなくても5行目のデリゲート型の宣言で引数の型は明らかなためです。

処理が1行の場合には{}およびreturn文が省略できる

処理が1行の場合に限り{}とreturn文が省略可能です。この書き方を「式形式のラムダ」と呼びます。

コード

using System;

internal class Program
{
    delegate int TestDel(int x, int y);

    static void Main(string[] args)
    {
        //ラムダ式
        TestDel delVar = (a, b) => a + b;

        int ans = delVar(2, 3);
        Console.WriteLine("ans:{0}", ans);
    }
}

出力結果

ans:5

上記コードの10行目のように、処理が1行で済む場合には{}を省略して返値だけを書くことができます。{}を省略する場合には、むしろreturnは書いてはいけません。

引数が一つの場合には( )を省略できる

引数が一つの場合には、引数を囲む( )を省略できます。

コード

using System;

internal class Program
{
    delegate void TestDel(int x);

    static void Main(string[] args)
    {
        //ラムダ式
        TestDel delVar = a => Console.WriteLine("a:{0}が出力されました", a);

        delVar(2);
    }
}

出力結果

a:2が出力されました

上記コードの10行目ように、引数が一つの場合には( )も省略可能です。( )をつけてもかまいません。なお、この例では戻り値のないデリゲート型を定義していますので、ラムダ式の処理も戻り値を持ちません。

なお、引数がない場合には、下記のように空の()を記述します。

TestDel delVar = () => Console.WriteLine("こんにちは");

ラムダ式をメソッドの引数にする

ラムダ式をメソッドの引数にする場合があります。それはメソッドの引数がデリゲート型の場合です。デリゲートはメソッドを変数として扱う仕組みです。デリゲートについてはわからない場合はコチラもぜひ参照ください。

ラムダ式をメソッドに引数にする場合の例としてList<T>クラスのRemoveAllメソッドがあります。RemoveAllメソッドは条件に一致するList要素をすべて削除するメソッドです。このメソッドは定義済みデリゲートであるPredicate<T>型の引数を指定します。Predicate<T>型はT型の引数ひとつとbool型の戻り値を持つ定義済みデリゲートです。この引数をラムダ式で指定できます。
このラムダ式で各要素の値をbool判定しtrueの場合には削除、falseの場合には削除しない、という処理を行うのがRemoveAllメソッドです。

定義済みデリゲートについては、こちらで詳細に説明していますのでご覧ください。

コード

using System;
using System.Collections.Generic;

internal class Program
{
    static void Main(string[] args)
    {
        var lst = new List<string> { "Japan", "Vietnam", "India", "USA", "Canada", "Mexico" };
        Console.WriteLine("{0}:[{1}]", nameof(lst), string.Join(" ", lst));  //リストの表示

        lst.RemoveAll(item => item.Contains("a"));
        Console.WriteLine("{0}:[{1}]", nameof(lst), string.Join(" ", lst));  //リストの表示
    }
}

出力結果

lst:[Japan Vietnam India USA Canada Mexico]
lst:[USA Mexico]

上記コードの11行目でRemoveAllメソッドの引数がラムダ式となっています。11行目は下記のようにしても同じです。

        Predicate<string> pdDel = item => item.Contains("a");
        lst.RemoveAll(pdDel);

終わりに

いかがだったでしょうか?ここでは匿名メソッドとラムダ式について、わかりやすく解説しました。ラムダ式で記述できない匿名メソッドはありませんから、コーディングではラムダ式を使っていきましょう。

なお、ラムダ式に似た表現表現方法に式形式のメンバーがあるので、興味があればコチラも参照ください。

ABOUT ME
しかすけ
日々是好日。何とか何とか生きてます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です