(.Net)デリゲートを自作するメリットがようやく分かってきた

今まで、例えばジェネリック型のListクラスのFindメソッドなどの述語として用いる部分でしかデリゲートは使っていませんでした。(それらも主に匿名メソッドを使ってきました。匿名メソッドを使った例は、(vb.net)VB.NetではList.Findとかのデリゲートの実装が必要なメソッドは使えない!/a>,(.Net)List.Sortの使い方,(.Net)Stringの仕様にやられた 等を参照。)

しかし、よーやくデリゲートを自作するメリットがようやく分かってきました。
(デリゲートとは、メソッドを参照するための型で、変数にメソッドを入れるようなものです。関数ポインタをイメージするといいかもしれません)

例えば下記のような処理があるとします。

private void button1_Click(object sender, EventArgs e){
//共通処理
//このメソッド独特の処理(上記の共通処理の結果を用いる)
//共通処理
}
 
private void button2_Click(object sender, EventArgs e){
//共通処理
//このメソッド独特の処理(上記の共通処理の結果を用いる)
//共通処理
}

この場合、共通処理が冗長しているので開発者の考えとしては、まず、下記のように別メソッドで処理するかもしれません。
要は、条件分岐で処理が違うところだけ分けてやろうという話です。

private void button1_Click(object sender, EventArgs e){
funcA(1,他の引数);
}
 
private void button2_Click(object sender, EventArgs e){
funcA(2,他の引数);
}
 
private void funcA(int Flg,他の引数){
//共通処理
if(Flg==1){ //swithc文を使うケースも有るかも
button1_Click独特の処理
}else if(Flg==2){
button2_Click独特の処理
}
//共通処理
}

しかし、これはあまりきれいといえませんし、コードの修正があったときにもフラグを新しくふらないといけません。

ここで、デリゲートが威力を発揮します。
呼び出し元(buttonのイベントハンドラ)で、デリゲート型変数にメソッドを代入することで変数とメソッドの関連付けを行います。
後は、その変数を呼び出せば、関連付けされたメソッドが動くというわけですね。
下記のようなイメージです。

delegate void DelegateTest(引数);
 
private void button1_Click(object sender, EventArgs e){
DelegateTest delgt = new DelegateTest(処理button1_Click時 のメソッド名)
funcA(delgt,他の引数);
}
 
private void button2_Click(object sender, EventArgs e){
DelegateTest delgt = new DelegateTest(処理button2_Click時 のメソッド名)
funcA(他の引数);
}
 
private void funcA(DelegateTest delgt,他の引数){
//共通処理
delgt(引数);
//共通処理
}
 
private void 処理button1_Click時(引数){
button1_Click独特の処理
}
 
private void 処理button2_Click時(引数){
button2_Click独特の処理
}


具体的なコードを書くと下記のようになります。(C#)

//ボタンイベントハンドラ
private void button1_Click(object sender, EventArgs e){
//CalcDelegate型変数に、足し算用CalcAdditionメソッド代入
CalcDelegate calcDlgt = new CalcDelegate(CalcAddition);
Calc(calcDlgt, 10, 3);
}
private void button2_Click(object sender, EventArgs e){
//CalcDelegate型変数に、引き算用CalcAdditionメソッド代入
//C#2.0からは下記のように書ける
CalcDelegate calcDlgt = CalcSubtraction;
Calc(calcDlgt, 5, 1);
}
private void button3_Click(object sender, EventArgs e){
//CalcDelegate型変数に、掛け算用CalcAdditionメソッド代入
CalcDelegate calcDlgt = CalcMultiplication;
Calc(calcDlgt, 1, 1);
}
 
//デリゲート型を定義。
delegate int CalcDelegate(int x , int y);
 
/// <summary>計算(足し算)だけ行う。デリゲート経由で呼び出される。</summary>
private int CalcAddition(int x, int y){
return x + y;
}
/// <summary>計算(引き算)だけ行う。デリゲート経由で呼び出される。</summary>
private int CalcSubtraction(int x, int y){
return x - y;
}
/// <summary>計算(掛け算)だけ行う。デリゲート経由で呼び出される。</summary>
private int CalcMultiplication(int x, int y) {
return x * y;
}
 
private void Calc(CalcDelegate calcDlgt,int x,int y){
try {
//いろいろな共通処理...
//共通処理の例としてxとyをインクリメントする
x++; y++;
int res = calcDlgt(x, y);
Console.WriteLine("計算結果:" + res);
//いろいろな共通処理...
} catch {
//本来はここに例外処理を実装
}
}

ただ、デリゲート経由で呼び出すメソッド達が、引数と戻り値の型が一致してないといけないのがちょっと使いづらいですね。

参考:
デリゲート,マルチキャストデリゲート,非同期呼び出し,匿名メソッド,ラムダ式,covariance,contravariance,C#,.NET Framework
IT.NET C# - デリゲート (delegate) を使うメリット考える (1)
@IT:連載 改訂版 C#入門 第13章 処理を委譲するデリゲート
IT.NET C# - デリゲート (delegate) を使うメリット考える (2)
IT.NET C# - デリゲート (delegate) を使うメリット考える (3)
[PR]
by Jehoshaphat | 2011-10-19 23:54 | .Net開発 | Trackback | Comments(1)
トラックバックURL : http://jehupc.exblog.jp/tb/16034401
トラックバックする(会員専用) [ヘルプ]
※このブログはトラックバック承認制を適用しています。 ブログの持ち主が承認するまでトラックバックは表示されません。
Commented by 初見 at 2015-06-01 11:16 x
記述の誤りがありました

private void button2_Click(object sender, EventArgs e){
DelegateTest delgt = new DelegateTest(処理button2_Click時 のメソッド名)
funcA(他の引数);
}

の所ですが、

× funcA(他の引数);
○ funcA(delgt,他の引数);

ですね


<< (.Net)ジェネリックデリゲ... (Linux)MySQLのバッ... >>