連載

C#入門

第17回 処理を委譲するdelegate

(株)ピーデー
川俣 晶
2001/12/07


戻り値と引数が合えば委譲できる

 delegateは、対象となるメソッドにprivateキーワードなどが付加されてアクセス権が与えられていない場合などを除き、戻り値と引数が合えば委譲できる。別クラスの異なる名前のメソッドであっても、戻り値と引数だけ合っていれば委譲できる。以下は、まったく無関係な別クラスの異なる名前のメソッドに委譲した例である。

 1: using System;
 2:
 3: namespace ConsoleApplication24
 4: {
 5:   delegate void Sample( int x, int y );
 6:   class Class2
 7:   {
 8:     public int result;
 9:     public void methodMult( int x, int y )
10:     {
11:       result = x * y;
12:     }
13:   }
14:   class Class3
15:   {
16:     public int result;
17:     public void methodPlus( int x, int y )
18:     {
19:       result = x + y;
20:     }
21:   }
22:   class Class1
23:   {
24:     static void Main(string[] args)
25:     {
26:       Class2 instance1 = new Class2();
27:       Class3 instance2 = new Class3();
28:       Sample d1 = new Sample( instance1.methodMult );
29:       Sample d2 = new Sample( instance2.methodPlus );
30:       d1(2,3);
31:       d2(4,5);
32:       Console.WriteLine( instance1.result );
33:       Console.WriteLine( instance2.result );
34:     }
35:   }
36: }
異なるクラスのインスタンスに対するdelegateを使用したサンプル・プログラム5
Class2とClass3はまったく無関係なクラスであるが、同一の型のdelegateを作成することができる。

 これを実行すると以下のようになる。

サンプル・プログラム5の実行結果
メソッドの戻り値と引数だけ合っていれば、同一の型のdelegateを作成することができ、それを呼び出すことができる。

 このサンプル・ソースはここまで説明した知識だけで読みとれると思う。このように、delegateは自由度の高い機能なのである。

継承でも実現できるか?

 異なるクラスのメソッドを1つのメソッド呼び出しで扱う、というのは何もdelegateだけが持つ機能ではない。クラスの継承や、interfaceの機能を使って実現することもできる。以下は継承を使って実現してみた例である。これをdelegateを使った場合と比較して考えてみよう。

 1: using System;
 2:
 3: namespace ConsoleApplication25
 4: {
 5:   abstract class ClassBase
 6:   {
 7:     public abstract int method( int x, int y );
 8:   }
 9:   class ClassMult : ClassBase
10:   {
11:     public override int method( int x, int y )
12:     {
13:       return x*y;
14:     }
15:   }
16:   class ClassPlus : ClassBase
17:   {
18:     public override int method( int x, int y )
19:     {
20:       return x+y;
21:     }
22:   }
23:
24:   class Class1
25:   {
26:     public static void calc( int x, int y, ClassBase instance )
27:     {
28:       int result = instance.method(x,y);
29:       Console.WriteLine( result );
30:     }
31:     static void Main(string[] args)
32:     {
33:       ClassMult instance1 = new ClassMult();
34:       ClassPlus instance2 = new ClassPlus();
35:       calc( 2, 3, instance1 );
36:       calc( 2, 3, instance2 );
37:     }
38:   }
39: }
クラスの継承を用いてdelegateの機能を真似たサンプル・プログラム6
基底クラスでabstractなメソッドを定義し、それをオーバーライドしたメソッドに処理を記述する。

 これを実行すると以下のようになる。

サンプル・プログラム6の実行結果
実行結果はサンプル・プログラム2とまったく同じである。

 このサンプル・ソースは、28行目のメソッド呼び出しによって、掛け算をしたり、足し算をしたりする。機能面では、これまで説明したサンプル・ソースと似ているが、コーディングにはいくつもの違いが見られる。まず、継承を使う方法ではメソッド名を統一しておく必要がある。また、あらかじめ、基底クラス(ClassBase)でabstractなメソッド宣言をしておき、機能をオーバーライドする場合はoverrideキーワードを付けてメソッドを記述する必要がある。戻り値と引数が合っていれば使用できるdelegateと比較すれば、制約は大きいといえる。さらに、28行目を見て分かるとおり、具体的に呼び出すインスタンスとメソッドが直接記述されているのも同然であり、代表者としての役割を果たしているとはいい難い。

 このようにdelegateは、delegateという1つの機能であって、継承やinterfaceとは異なる特徴を持っている。これらは、適切に使い分けられるべきものなのである。


 INDEX
  第17回 処理を委譲するdelegate
    1.delegateとは何か
    2.staticなメソッドへの委譲
  3.戻り値と引数が合えば委譲できる
    4.delegateをオブジェクトとして使う
    5.移譲先リストの変更
 
「C#入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間