次の方法で共有


デリゲートとラムダ

デリゲートは、特定のパラメーター リストと戻り値の型を持つメソッドへの参照を表す型を定義します。 パラメーター リストと戻り値の型が一致するメソッド (静的またはインスタンス) を、その型の変数に割り当てた後、(適切な引数を使用して) 直接呼び出すか、引数自体として別のメソッドに渡してから呼び出すことができます。 次の例では、デリゲートの使用を示します。

using System;
using System.Linq;

public class Program
{
    public delegate string Reverse(string s);

    static string ReverseString(string s)
    {
        return new string(s.Reverse().ToArray());
    }

    static void Main(string[] args)
    {
        Reverse rev = ReverseString;

        Console.WriteLine(rev("a string"));
    }
}
  • public delegate string Reverse(string s);行は、文字列パラメーターを受け取り、文字列パラメーターを返すメソッドのデリゲート型を作成します。
  • static string ReverseString(string s) メソッドは、定義されたデリゲート型とまったく同じパラメーター リストと戻り値の型を持ち、デリゲートを実装します。
  • Reverse rev = ReverseString;行は、対応するデリゲート型の変数にメソッドを割り当てることができることを示しています。
  • Console.WriteLine(rev("a string"));行は、デリゲート型の変数を使用してデリゲートを呼び出す方法を示しています。

開発プロセスを効率化するために、.NET には、プログラマが再利用でき、新しい型を作成する必要がないデリゲート型のセットが含まれています。 これらの型は Func<>Action<> 、および Predicate<>であり、新しいデリゲート型を定義しなくても使用できます。 3 つの型には、使用を意図した方法と関係があるいくつかの違いがあります。

  • Action<> は、デリゲートの引数を使用してアクションを実行する必要がある場合に使用されます。 カプセル化するメソッドは値を返しません。
  • Func<> は通常、変換が手元にある場合に使用されます。つまり、デリゲートの引数を別の結果に変換する必要があります。 プロジェクションは良い例です。 カプセル化するメソッドは、指定した値を返します。
  • Predicate<> は、引数がデリゲートの条件を満たすかどうかを判断する必要がある場合に使用されます。 また、 Func<T, bool>として記述することもできます。つまり、メソッドはブール値を返します。

上記の例を見て、カスタム型の代わりに Func<> デリゲートを使用して書き換えることができます。 プログラムは引き続きまったく同じ実行を続けます。

using System;
using System.Linq;

public class Program
{
    static string ReverseString(string s)
    {
        return new string(s.Reverse().ToArray());
    }

    static void Main(string[] args)
    {
        Func<string, string> rev = ReverseString;

        Console.WriteLine(rev("a string"));
    }
}

この簡単な例では、 Main メソッドの外部で定義されたメソッドを持つことは少し余分に思えます。 .NET Framework 2.0 では 、匿名デリゲートの概念が導入されました。これを使用すると、追加の型やメソッドを指定しなくても "インライン" デリゲートを作成できます。

次の例では、匿名デリゲートによってリストがフィルター処理され、偶数だけが表示され、コンソールに出力されます。

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main(string[] args)
    {
        List<int> list = new List<int>();

        for (int i = 1; i <= 100; i++)
        {
            list.Add(i);
        }

        List<int> result = list.FindAll(
          delegate (int no)
          {
              return (no % 2 == 0);
          }
        );

        foreach (var item in result)
        {
            Console.WriteLine(item);
        }
    }
}

ご覧のように、デリゲートの本文は、他のデリゲートと同様に、単なる式のセットです。 ただし、別の定義ではなく、List<T>.FindAll メソッドの呼び出しでアドホックに導入しました。

ただし、この方法でも、捨てることができるコードはまだたくさんあります。 ここで ラムダ式が機能します 。 ラムダ式 、つまり略して "ラムダ" は、言語統合クエリ (LINQ) の主要な構成要素の 1 つとして C# 3.0 で導入されました。 これらは、デリゲートを使用するためのより便利な構文です。 パラメーター リストとメソッド本体を宣言しますが、デリゲートに割り当てられない限り、独自の正式な ID はありません。 デリゲートとは異なり、これらはイベント登録の右側、またはさまざまな LINQ 句やメソッドで直接割り当てることができます。

ラムダ式はデリゲートを指定するもう 1 つの方法であるため、上記のサンプルを書き直して、匿名デリゲートの代わりにラムダ式を使用できるようにする必要があります。

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main(string[] args)
    {
        List<int> list = new List<int>();

        for (int i = 1; i <= 100; i++)
        {
            list.Add(i);
        }

        List<int> result = list.FindAll(i => i % 2 == 0);

        foreach (var item in result)
        {
            Console.WriteLine(item);
        }
    }
}

前の例では、使用されるラムダ式は i => i % 2 == 0。 ここでも、デリゲートを使用するための便利な構文です。 内部で何が起こるかは、匿名デリゲートで行われることと似ています。

ここでも、ラムダは単なるデリゲートです。つまり、次のコード スニペットに示すように、問題なくイベント ハンドラーとして使用できます。

public MainWindow()
{
    InitializeComponent();

    Loaded += (o, e) =>
    {
        this.Title = "Loaded";
    };
}

このコンテキストの += 演算子は、 イベントのサブスクライブに使用されます。 詳細については、「イベントを登録および登録解除する方法」を参照してください。

詳細な読み取りとリソース