2008年10月9日

Predicate デリゲート

配列の中から、「ある条件に一致するものを探す」ような場面ではSystem.Array クラスのジェネリックメソッドが使える。例えば

  • Find:ある条件に一致する要素を探す
  • Exists:ある条件に一致する要素が存在するかどうかを調べる
  • FindIndex:ある条件に一致する要素のインデックスを取得

など。これらのメソッドの引数にPredicateデリゲートを渡す必要がある。このデリゲートには「ある条件に一致かどうか」を返す処理を実装する。

public void Execute()
{
    string[] animals ={ "cat", "dog", "pig", "bear" };

    Console.WriteLine(Array.Exists(animals, new Predicate(StartWithP)).ToString());
    Console.WriteLine(Array.Find(animals, new Predicate(StartWithP)));
    Console.WriteLine(Array.FindIndex(animals, new Predicate(StartWithP)).ToString());
}

//"p"で始まるかどうかを判定する
private bool StartWithP(string value)
{
    return (value.StartsWith("p"));
}

ただし、これだと「ある条件」が固定となってしまう。
条件を動的にするには以下のように変数を使用すればよいが、以下のようにExecuteメソッドの外に宣言しなければならない。

private string _condition;

public void Execute()
{
    string[] animals ={ "cat", "dog", "pig", "bear" };
    _condition = "p";

    Console.WriteLine(Array.Exists(animals, new Predicate(StartWith)).ToString());
    Console.WriteLine(Array.Find(animals, new Predicate(StartWith)));
    Console.WriteLine(Array.FindIndex(animals, new Predicate(StartWith)).ToString());
}

//指定の文字列で始まるかどうかを判定
private bool StartWith(string value)
{
    return (value.StartsWith(_condition));
}

ここはこの変数のスコープをExecuteメソッド内としたいところ。
なるほど、ここで匿名メソッドが使える。匿名メソッドではその外部のメソッド内のローカル変数にもアクセス可能であるため、条件を示す変数もExecuteメソッド内に宣言できる。

public void Execute()
{
    string[] animals ={ "cat", "dog", "pig", "bear" };
    string condition = "p";

    //匿名メソッドで指定文字列から始まるかを返すメソッドを定義
    Predicate d = delegate(string value) { return (value.StartsWith(condition)); };
    Console.WriteLine(Array.Exists(animals, d).ToString());
    Console.WriteLine(Array.Find(animals, d));
    Console.WriteLine(Array.FindIndex(animals, d).ToString());
}

これは便利だ

0 件のコメント:

コメントを投稿