第1分:デリゲート
一部の教材やブログでは、デリゲートについて触れると必ずイベントが登場します。イベントはデリゲートのインスタンスですが、理解を簡単にするため、今日はデリゲートだけを扱い、イベントは扱いません。まずは次のコードをご覧ください。
以下のコードは、デリゲートアプリケーションのデモを完成させています。デリゲートは3つのステップで構成されます。
class Program
{
// step01:まず delegate を使用してデリゲートを定義する。
public delegate int CalculatorAdd(int x, int y);
static void Main(string[] args)
{
// step03:このメソッドを使用してデリゲートをインスタンス化する。
CalculatorAdd cAdd = new CalculatorAdd(Add);
// int result = cAdd(5, 6);
int result = cAdd.Invoke(5, 6);
}
// step02:デリゲートに対応するメソッドを宣言する。
public static int Add(int x, int y)
{
return x + y;
}
}
step01:まず delegate を使用してデリゲートを定義する。- step02:デリゲートに対応するメソッドを宣言する。
- step03:このメソッドを使用してデリゲートをインスタンス化する。
これでデリゲートアプリケーションが完成し、デリゲートを呼び出すことができます。
第2分:匿名メソッド
前の分で、デリゲートアプリケーションを完成させるには3ステップが必要で、1つでも欠けてはいけないことがわかりました。大きなステップを踏もうとすると、リスクが伴います。しかしマイクロソフトはそのリスクを恐れず、3ステップを2ステップにしようとしました。そこで匿名メソッドを使用して上記の3ステップを簡略化しました。匿名メソッドは、C#では必須のものではなく、C#をさらに便利にするための、いわゆる「シンタックスシュガー」です。
class Program
{
// step01:まず delegate を使用してデリゲートを定義する。
public delegate int CalculatorAdd(int x, int y);
static void Main(string[] args)
{
// step02:delegate(int x, int y) { return x + y; } のように記述して、メソッドをデリゲートに割り当てる
CalculatorAdd cAdd = delegate (int x, int y) { return x + y; };
int result = cAdd.Invoke(5, 6);
}
}
- step01:まず delegate を使用してデリゲートを定義する。
- step02:
delegate(int x, int y) { return x + y; }のように記述して、メソッドをデリゲートに割り当てる。この記述が匿名メソッドである。
これで、3ステップが2ステップに減ったことに驚くでしょう。
第3分:ラムダ式
本来単純なプログラムにいくつかの delegate キーワードを追加すると、コードが急に難解になり、理解する人が減ります。そのため、これを給与交渉の材料にすることもできます。しかし、マイクロソフトの設計哲学はシンプルで使いやすいことです。そこでマイクロソフトは delegate(int x, int y) { return x + y; } という匿名メソッドをさらに簡略化しようと試み、ラムダ式が登場しました。以下に、いくつかのラムダ式の書き方を示します。
class Program
{
public delegate int CalculatorAdd(int x, int y);
static void Main(string[] args)
{
// 方法1:
CalculatorAdd cAdd1 = (int x, int y) => { return x + y; };
int result1 = cAdd1(5, 6);
// 方法2:
CalculatorAdd cAdd2 = (x, y) => { return x + y; };
int result2 = cAdd2(5, 6);
// 方法3:
CalculatorAdd cAdd3 = (x, y) => x + y;
int result3 = cAdd2(5, 6);
}
}
第4分:ジェネリックデリゲート
.NET のバージョンが上がるにつれて、新しいバージョンは旧バージョンと差別化する必要があります。さもなければ、マイクロソフトのエンジニアが上司に説明できません。そこでマイクロソフトはまた新たな機能を導入しました。
class Program
{
static void Main(string[] args)
{
// 方法1:
Func<int, int, int> cAdd1 = (int x, int y) => { return x + y; };
int result1 = cAdd1(5, 6);
// 方法2:
Func<int, int, int> cAdd2 = (x, y) => { return x + y; };
int result2 = cAdd2(5, 6);
// 方法3:
Func<int, int, int> cAdd3 = (x, y) => x + y;
int result3 = cAdd2(5, 6);
}
}
匿名メソッドでもラムダ式でも、デリゲートアプリケーションを完成させるには、デリゲートを定義するステップと、メソッドを使用してデリゲートをインスタンス化するステップの2つを避けられません。マイクロソフトはこれら2つのステップを1つに統合しました。Func を使用してデリゲートの定義を簡略化します。
これで、デリゲートアプリケーションは Func<int, int, int> cAdd3 = (x, y) => x + y; という1行で完了します。この Func がいわゆるジェネリックデリゲートです。
第5分:式木
式木は実際にはデリゲートとはあまり関係がありません。無理やり関係づけるなら、式木はデリゲートを格納するコンテナです。より専門的に言えば、式木はラムダ式を格納するためのデータ構造です。ラムダ式が必要なときは、式から取り出して Compile() を呼び出すだけで使用できます。次のコードを参照してください。
class Program
{
static void Main(string[] args)
{
Expression<Func<int, int, int>> exp = (x, y) => x + y;
Func<int, int, int> fun = exp.Compile();
int result = fun(2, 3);
}
}