C Sharpの基礎 - デリゲート
概要
- デリゲートとは、メソッドを参照する型である。
- LINQ等で使用される
Action<T>
やFunc<T, TResult>
は、デリゲート型の1つである。 - デリゲート型を作成するためだけに、クラスメソッドかインスタンスメソッドを定義するのは面倒である。
- 匿名関数を使用すれば、メソッドを定義せずにインラインに処理を記述して、デリゲート型を作成することができる。
- 匿名関数には2種類あり、その1つがラムダ式である。(正確には、C#のラムダ式はシンタックスであり、匿名関数ではない)
- ラムダ式はデリゲート型の作成だけでなく、式ツリー型の生成にも使用できる。
- 匿名関数は、コンパイラがクラスメソッド・インスタンスメソッド・クラス等を内部的に作成して、それを参照するデリゲートを作っている。
デリゲート
C#におけるデリゲートとは、メソッドを参照する型のことである。
メソッドを参照するデリゲートを、引数として渡したり、戻り値を返している。
このデリゲートの存在が、LINQやReactive Extensionsを支えている。
全てのデリゲートは、Delegate型から派生した型である。
デリゲート型を作成するには、以下のようにdelegate
キーワードを使用する。
これにより、Delegate型(正確には、MulticastDelegate型)のサブクラスが定義される。
// int型を引数にとり、int型を返すメソッドを参照するデリゲート型
public delegate int IntToInt(int value);
// string型を引数にとり、int型を返すメソッドを参照するデリゲート型
public delegate int StringToInt(string value);
// 引数が無く、int型を返すメソッドを参照するデリゲート型
public delegate int ReturnInt();
// int型を引数にとり、戻り値が無いメソッドを参照するデリゲート型
public delegate void ActionInt(int value);
// 2つのint型を引数にとり、int型を返すメソッドを参照するデリゲート型
public delegate int IntIntToInt(int value0, int value1);
次に、クラスメソッドを参照するデリゲートのインスタンスを作成する。
// インスタンスを作成するデリゲート型
// int型を引数にとり、int型を返すメソッドを参照するデリゲート型
public delegate int IntToInt(int value);
// 参照するクラスとメソッド
public class Calculator
{
public static int AddOne (int value)
{
return value + 1;
}
}
// デリゲートのインスタンスを作成
// AddOneメソッドを参照するIntToInt型
IntToInt addOne = Calculator.AddOne;
// Calculatorクラス内ならば、以下の記述でもよい
// IntToInt addOne = AddOne;
最後に、インスタンスメソッドを参照するデリゲートのインスタンスを作成する。
デリゲートがインスタンスメソッドを参照する場合、どのインスタンスのメソッドを参照しているかの情報が必要である。
デリゲートは、対象のインスタンスへの参照も内部的に保持しており、
そのインスタンスにアクセスするためのプロパティとして、Delegate
型はTarget
プロパティを持っている。
// インスタンスを作成するデリゲート型
// int型を引数にとり、int型を返すメソッドを参照するデリゲート型
public delegate int IntToInt(int value);
public class Multiplier
{
readonly int number;
public Multiplier(int number)
{
this.number = number;
}
public int Calc(int v)
{
return number * v;
}
}
MultiplierクラスのインスタンスのCalcメソッドを参照するデリゲートのインスタンスを作成するには、以下のように記述する。
Multiplier doubler = new Multiplier(2); // Calcメソッドは、引数で渡した数の2倍の数を返す
IntToInt doublerIntToInt = doubler.Calc; // doublerのCalcを参照するデリゲートを生成
Multiplier trippler = new Multiplier(3); // Calcメソッドは引数で渡した数の3倍の数を返す
IntToInt tripplerIntToInt = trippler.Calc; // tripplerのCalcを参照するデリゲートを生成
ActionとFunc
Action<T>は、T型の引数をとり、戻り値は返さないメソッドを参照するジェネリックなデリゲート型である。
Func<T, TResult>は、T型の引数をとり、TResult型を返すメソッドを参照するジェネリックなデリゲート型である。
これらは、デリゲート型の1つである。
以下の例では、Func<T, TResult>型のデリゲートのインスタンスを生成している。
public static int AddOne(int value)
{
return value + 1;
}
public static int GetLength(string value)
{
return value.Length;
}
public static void Main(string[] args)
{
// intを引数に取りintを返すAddOneメソッドを参照するデリゲートを生成
Func<int, int> addOneDelegate = AddOne;
// stringを引数に取りintを返すGetLenghtメソッドを参照するデリゲートを生成
Func<string, int> GetLengthDelegate = GetLength;
// doubleを引数に取りdoubleを返すSystem.Math.Absメソッドを参照するデリゲートを生成
Func<double, double> doubleFloatDelegate = Math.Abs;
}
Func<T, TResult>はジェネリックなデリゲート型なので、適切に型パラメータを設定すれば、様々なメソッドを参照できます。
Func<T, TResult>以外のジェネリクなデリゲート型には、更に多くの引数をとるAction型やFunc型のデリゲート型も存在する。
これらのジェネリックなデリゲート型は、Action<T>型を除き、C# 3.0 / .NET 3.5で追加された。
以下に、メソッドを参照することができるジェネリクなデリゲート型の例を示す。
- Action型
- 引数とらず、戻り値を返さないメソッドを参照するデリゲート型
- Action<T>型
- T型の引数をとり、戻り値を返さないメソッドを参照するデリゲート型
- Action<T1, T2>型
- T1型、T2型の引数をとり、戻り値を返さないメソッドを参照するデリゲート型
- Func<TResult>型
- 引数とらず、TResult型の戻り値を返すメソッドを参照するデリゲート型
- Func<T1, T2, TResult>型
- T1型、T2型の引数をとり、TResult型の戻り値を返すメソッドを参照するデリゲート型
また、Action型やFunc型以外のデリゲート型も存在する。
LINQ等ではAction型やFunc型が多く使用されるが、それら以外のデリゲート型もクラスライブラリに存在する。
Predicate<T>
型というデリゲート型もその1つである。
このデリゲート型は、ListクラスのFindAllメソッドの引数として使用されており、ListクラスのConvertAllメソッド等でも使用されている。
他のデリゲート型には、Convertor<TInput, TOutput>
型、ListクラスのSortメソッドで使用されているComparison<T>
型等がある。