みなさんは、デリゲートを知っていますか?おそらく、C#を勉強し始めて間もなくしたら、デリゲートという言葉を聞くようになるかと思います。
例えば、変数に値を代入するように、関数を変数に格納して、ループ処理で回せたらいいのに…って思ったことありませんか??まさに、それができるのがデリゲートです!
少し難しく感じるかもしれませんが、使えれば便利なものです。サンプルをもとに、使い方を覚えましょう。
目次
デリゲートとは
デリゲートは、引数に関数(メソッド)を受けとることができるデータ型(参照型) の一種で、delegateキーワードを使って、関数を代入できる変数を宣言することが可能です。
ちなみに、delegateの意味は「委譲」や「代表」です。
デリゲートは直接メソッドを呼び出すのではなく、代表者に処理を委譲します。代表者は、処理機能自体は持っておらず、そのメソッドに処理要求を渡します。
デリゲートはどんなときに使うの?
呼び出し方はそのままで、呼び出す処理(メソッド)を動的に変えたいときなど。
例えば、以下のような処理A、処理Bがあったとします。//登録処理aと//登録処理b以外は同じ処理です。こんなとき、処理ABを1つにまとめれればなぁと思いませんか?
例えば、処理ABを1つの共通処理にして、引数(フラグ)を使用して、if文で// 登録処理aを実行するか、//削除処理bを実行するかを分岐して実行することができますね。
でも、例えば処理C()が増えたらどうでしょう??if文の分岐を追加してもいいですけど、共通処理自体を修正することになるので、あまり良くはありませんね。
こういう場合は、デリゲートを使用することで解決できます!処理の変更や追加等に柔軟に対応でき、上記の修正よりバグの発生を減らし、テストの効率化になります。
ただし、デリゲートを使うのには条件(後述)があるので、注意しましょう。
private void 登録処理A()
{
string[] array = new string[]{"a","b","c"};
foreach(string s in array)
{
// 登録処理a
InsertTableA(s);
}
}
private void 登録処理B()
{
string[] array = new string[]{"a","b","c"};
foreach(string s in array)
{
// 登録処理b
InsertTableB(s);
}
}
デリゲートの使い方
・「delegate」キーワードでデリゲート型の変数を宣言します。
・メソッドの引数とそのデータ型、戻り値のデータ型だけを定義します。
処理は記述しません。
・戻り値の型、デリゲート名、引数の定義、と通常のメソッドの定義と同じように記述します。
例)
delegate 戻り値の型 デリゲート型名(引数リスト);
// 引数なし、戻り値なし
delegate void Sample();
// 引数あり、戻り値なし
delegate void Sample(string name);
// 引数あり、戻り値あり
delegate string Sample(string name);
デリゲートを使用する条件
・delete型で宣言した変数に代入できるのは、delegate型と同じ引数(数、型)、戻り値が同一の関数のみです。
引数なし、戻り値なしのDelegate
// デリゲートの定義
private delegate void InsertTable();
private void 登録処理A() {
// InsertTable型の変数itaを定義
// 関数InsertTableAを代入
InsertTable ita = new InsertTable(InsertTableA);
RegistData(ita);
}
private void 登録処理B() {
// InsertTable型の変数itbを定義
// 関数InsertTableBを代入
InsertTable itb = new InsertTable(InsertTableB);
RegistData(itb);
}
// 共通処理
// 引数にInsertTable型の関数を受け取る
private void RegistData(InsertTable ifunc) {
string[] array = new string[]{"a","b","c"};
foreach(string s in array)
{
// 受け取った関数を実行(登録処理)
ifunc();
}
}
private void InsertTableA() {
// 登録処理a
}
private void InsertTableB() {
// 登録処理b
}
引数あり、戻り値ありのDelegate
// デリゲートの定義
public delegate string MyDelegate(string sei, string name);
static void Sample()
{
// MyDelegate型の変数createNameを定義
// 関数CreateNameを代入
MyDelegate createName = CreateName;
// 以下の宣言でも可
//MyDelegate createName = new MyDelegate(TestMethodA);
// createNameを実行すると、関数CreateNameが実行される
string nm = createName ("山田","花子");
}
//定義したデリゲートと同じ引数、戻り値のメソッド
static string CreateName(string s,string n)
{
return s + " " + n + "さん";
}
コールバック関数にDelegateを使用する
コールバック関数とは、何かの処理終了時に呼び出される関数のことです。
よく使われるプログラムの例として、あるURLにHTTPリクエストを行い、そのHTTPレスポンスに対して、任意の処理を行う…といったものです。Delegateを用いて、任意の処理を実行させます。
// デリゲートの定義
public delegate string Callback(HttpResponseMessage res);
static void Main(string[] args)
{
// Callback型の変数callbackを定義
// 関数GetStatusCodeを代入
Callback callback = GetStatusCode;
// HttpRequest関数を呼び出し
HttpRequest("https://~",callback);
}
// コールバック関数
static string GetStatusCode(HttpResponseMessage res)
{
// HTTPレスポンスのステータスコードを返す
return res.StatusCode.ToString();
}
// 第1引数に指定したURLにアクセスした際のHTTPレスポンスに対して、
// 第2引数で指定したCallback関数を実行する
async static void HttpRequest(String url, Callback callback)
{
using (HttpClient httpsClient = new HttpClient())
{
// HTTPレスポンスを取得
HttpResponseMessage res = await httpsClient.GetAsync(url);
// コールバック関数を実行
callback(res);
}
}
Delegateを使わなくても、Action型、Func型を使えば、Delegateの代用ができます。
その話はまた今度。。