C#でラムダ式を書く方法 #10_Predicateの使い方

当サイトではアフィリエイト広告を利用しています。

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

ここまででdelegateや匿名メソッドまでを解説してきました。今回はPredicate(プレディケート)に関して解説して行きます。

プレディケートというのはマイクロソフトのクラスライブラリーで既に定義されているdelegateです。

これまでのコード

これまでは次のような感じでdelegateを宣言して実装していました。LenCheckのような感じでdelegateを宣言し引数として使っていましたね。

「delegate bool LenCheck(string value);」の部分です。Predicateを使うと,この,delegateの宣言が不要になるというお話です。

delegate bool LenCheck(string value);

private string[] GetValue3(string[] values, LenCheck lenCheck)
{
    var result = new List();
    foreach (var val in values)
    {
        if (lenCheck(val))
        {
            result.Add(val);
        }
    }

    return result.ToArray();
}

C#2.0からは,Predicateが登場し引数が1つで,戻り値がboolの場合は,わざわざdelegateを宣言しなくても実装できるようになりました。

実際コードを書いた方が分かりやすいと思うのでさっそく書いていきましょう。 

ボタンの追加

いつものようにボタンを追加します。今回はbutton8です。

ボタンを貼り付けたら,ダブルクリックしてクリックイベントを自動生成させます。

private void button8_Click(object sender, EventArgs e)
{

}

GetValue8メソッドの作成

フリゲートを使うとどのような実数になるかを理解するために,以前作成したGetValue3の一部を改造して実装します。以前作成したGetValue3メソッドをコピーして貼り付け,新たにGetValue8メソッドとして実装します。メソッド名をGetValue8としておいてください。

private string[] GetValue8(string[] values, LenCheck lenCheck)
{
    var result = new List();
    foreach (var val in values)
    {
        if (lenCheck(val))
        {
            result.Add(val);
        }
    }

    return result.ToArray();
}

ボタンクリックイベント8の追記

それでは先ほど作成したbutton8_Clickイベントで,今作成したGetValue8メソッドを呼び出すように実装します。button8_Clickイベントは,以前作成したbutton6_Clickのコードをコピーしてきて貼り付け,GetValue3メソッド呼び出し部分を,GetValue8に変更しておきます。

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

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

GetValue8をPredicateに変更

こんばんはだと今までやってきたやり方と同じで,delegateであるLenCheckが必要な実装になっているため,LenCheckの部分を,Predicateに置き換えます。

GetValue8のLenCheckの部分をPredicate<string>に変更してください。

private string[] GetValue8(string[] values, Predicate lenCheck)
{
    var result = new List();
    foreach (var val in values)
    {
        if (lenCheck(val))
        {
            result.Add(val);
        }
    }

    return result.ToArray();
}

これでGetValue8では,LenCheckの使用がなくなり,Predicateに置き換わりました。これでもコンパイルがちゃんと通っているはずです。それでは何が起きているのか解説して行きましょう。

Predicateの定義とは

Predicateと実装した部分にカーソルをかざしてみてください。

次のように定義が表示されるはずです。

ここにPredicateの定義が記載されています。

「delegate bool System.Predicate<in T>(T obj)」

と書いてますね。

delegateで始まっていることからもわかるように,Predicateとはdelegateです。これはマイクロソフトのクラスライブラリーで予め定義されているdelegateということになります。なので定義を見れば,どのようなdelegateかということは理解できます。「delegate bool System.Predicate<in T>(T obj)」

delegateに続いてboolと書かれているため,戻り値はboolということです。「System.Predicate」の部分はdelegateの名前,<in T>(T obj)の部分は,引数が1つで,型は「T」になっています。要するに,使用する際に,型を指定できるということです。これはC#2.0で追加されたジェネリックという型指定の機能です。使用する際に型を指定すればよいということです。なので,このdelegateは「1つの任意の型を引数に渡すと,boolが返ってくる」という定義であるということがわかります。

おそらくマイクロソフトでは,このパターンが大変多く使われるということからこういった定義を作成したものと思います。引数の型は任意の型なので,intでもstringでもクラスでもいいため,非常に汎用的に使うことができます。また結果もboolなので,何かの判定に使うためのdelegateであれば使い勝手がいいわけです。

ということでこれまでやってきたLenCheckのdelegateは,引数がstringで戻り値がboolなので,Predicateに置き換えることができます。そういった理由から,GetValue8メソッドのLenCheckをPredicateに置き換えてもコンパイルエラーが出ないということです。

そして最も重要なことが,これまで宣言していたLenCheckの様なデリゲットが不要になるということです。

この部分ですね。

delegate bool LenCheck(string value);

なので,任意の引数1個と,戻り値がboolという型であればPredicateが使えるということです。 

実行

それでは実行して動作するかを確認してみましょう。

「CCC」と出力され,3文字の文字列のみが抽出されていることがわかります。LenCheckのdelegateがなくてもPredicateで動作しているということが確認できました。

わざわざdelegateを宣言しなくてもいいので,C#2.0の型指定の恩恵を受け,便利になったということです。次回はC#3.0の世界に入ります。さらに便利になりますので,ご期待ください。