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

C#でラムダ式を書く方法 #09_匿名メソッドの使いかた

前回まででdelegateの使いかたをやりました。引数1個のパターンと,引数にこのパターンをやりましたね。今回は匿名メソッドというものを解説して行きます。

ここまで解説してきたdelegateのやり方では,必ずメソッドを作る必要がありました。

メソッドは必ず必要か?

例えば次のような感じでShiki3やShiki4などのメソッドを作成して,GetValue5などのメソッドに引き渡していました。

private void button5_Click(object sender, EventArgs e)
{
    var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" };
    var result = GetValue5(values, 3, Shiki3);

    Console.WriteLine(string.Join(",", result));
}

private bool Shiki3(string value, int len)
{
    return value.Length == len;
}

必ずメソッドを書かないといけないことが大きな問題とはなりませんし,C#1.0では,この書き方しかできませんでした。しかしC#2.0では,匿名メソッドという機能が追加され,必ずしもメソッドを書かなくても良くなりました。例えば先述の例であれば,GetValue5メソッドに,Shiki3を引き渡していますが,このShiki3を1度しか使わない場合は,わざわざメソッド化をしなくても,GetValue5を呼び出すタイミングで,直接「式」を渡すことができれば非常に便利です。そうなればわざわざ「Shiki3」などというメソッド名を考える必要もなくなります。それを実現するために考え出された機能が「匿名メソッド」ということになります。 

ボタンの追加

匿名メソッドを実装するためにボタンを1つ追加します。button6とします。

匿名メソッド化前

作成したボタンをダブルクリックして,クリックイベントを自動生成し,生成された,button6_Clickの中に,以前作成したbutton3_Clickの内容をコピーして貼り付けます。GetValue3を呼び出しており,Shiki1をdelegateとして,引き渡しています。Shiki1メソッドは,以前作成したものと同じなので,書き足す必要はありません。

private void button6_Click(object sender, EventArgs e)
{
    var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" };
    var result = GetValue3(values, Shiki1);//ここのShiki1の部分を匿名メソッド化する

    Console.WriteLine(string.Join(",", result));
}

private bool Shiki1(string value)
{
    return value.Length == 3;
}

この状態でShiki1の部分を,匿名メソッドに変える方法を解説します。 

匿名メソッド化後

GetValue3の呼び出し部分のShiki1の部分を「匿名メソッド化」すると次のようになります。

private void button6_Click(object sender, EventArgs e)
{
    var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" };
    var result = GetValue3(values, 
        delegate (string value)
        {
            return value.Length == 3;
        }
        );

    Console.WriteLine(string.Join(",", result));
}

最初はわからない感じの書き方で,なんとなく抵抗があると思うので,順番に解説して行きます。

手順1

まずShiki1を引き渡していた部分を消します。

private void button6_Click(object sender, EventArgs e)
{
    var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" };
    var result = GetValue3(values,         );//Shiki1を消す

    Console.WriteLine(string.Join(",", result));
}

手順2

手順1で消した部分,つまり,GetValue3の第2引数「delegate」と書きます。

private void button6_Click(object sender, EventArgs e)
{
    var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" };
    var result = GetValue3(values, delegate );//delegateと書く

    Console.WriteLine(string.Join(",", result));
}

手順3

手順2で書いたdelegateの後にスペースを入れて,その後に,Shiki1メソッドの引数の部分からすべてをコピーして貼り付けます。

このような感じになります。

private void button6_Click(object sender, EventArgs e)
{
    var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" };
    var result = GetValue3(values,
                            delegate (string value)
                            {
                                return value.Length == 3;
                            }
                            );//Shiki1の引数以降の部分を書く

    Console.WriteLine(string.Join(",", result));
}

GetValue3の第1引数valuesのままで,続いて「カンマ」,第2引数に,前述の手順1から3を行い,このようにdelegateで始まるメソッド的な記述を引数に書きます。

先ほどの図の吹き出しのとおり,delegate以降には,引き渡したいメソッドを書いていますが,メソッド化をした際の,ちょうど引数の記述以降をすべて書いています。図の赤枠の部分です。それ以外の部分で言うと,まずメソッド名は不要です。だから匿名メソッドと言われます。戻り値のboolの部分は,「return value.Length == 3;」ということから,boolでることはコンパイラに伝わるため,これも匿名メソッドでは記載する必要がありません。アクセスレベルである「private」に関しても不要です。匿名メソッドは一度きりの使い捨てメソッドなので,外部から呼ばれるはずもなく,呼ぶも何も名前ななくて呼べないので,アクセスレベルは不要です。このような流れで匿名メソッドを記述することができました。

覚え方

少し特殊な書き方なので,最初は戸惑うと思いますが,覚え方は簡単です。

①「delegate」と記載。

②その後に,メソッドの引数以降を記載する

これだけです。最初はいきなり書けないと思うので,一旦Shiki1のように,普通にメソッド書いてから,匿名メソッド化することをお勧めします。慣れてきたら,いきなり書けるようになると思います。手順を踏んで考えていけば,「意外と簡単だ」と思えるようになると思います。

実行

実行して,動作するかを検証しましょう。

button6を押下すると,「CCC」と出力されます。これで,以前のShiki1の部分が実行されていることが確認できます。 

値を変えて確認する

これで匿名メソッドを書くことができました。使い捨てのメソッドであれば,わざわざメソッドを作成する必要がなく,「return value.Length == 3;」の部分を変更するだけで,いくらでも判定式を送り込むことができます。他の式も渡せることを確認してみましょう。

ボタンbutton7を追加して,ダブルクリックをして,クリックイベントを自動生成します。

private void button7_Click(object sender, EventArgs e)
{
    var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" };
    var result = GetValue3(values,
                            delegate (string value)
                            {
                                return value.Length >= 4;
                            }
                            );

    Console.WriteLine(string.Join(",", result));
}

delegateでreturnしている部分を好きな式に変更して変更して,匿名メソッドが正常に動作することを確認してみてください。ここでは「return value.Length >= 4;」としています。実行すると,次のように4文字以上の文字列が取得されることで,正常に動作していることが確認できます。

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