C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[2]: delegate


(過去ログ 96 を表示中)

[トピック内 3 記事 (1 - 3 表示)]  << 0 >>

■57350 / inTopicNo.1)  delegate
  
□投稿者/ TAKE (36回)-(2011/02/23(Wed) 14:04:48)

分類:[C#] 

TAKEと申します。
最近かなりの頻度で利用させていただいています。
今回もよろしくお願いいたします。

デリゲートについてなのですが
delegateの意味は理解したのですが
いまいち使いどころ、有用なところがわからないのですが
誰かdelegateの利点が自然に理解できるような
例題をだしてもらえないでしょうか?

その例題に対して
私がdelegate使わない方法でプログラムの回答を投稿しますので
その後
delegateを使った模範解答を投稿していただくという形です。

どうかよろしくお願いいたします。






引用返信 編集キー/
■57357 / inTopicNo.2)  Re[1]: delegate
□投稿者/ 魔界の仮面弁士 (2091回)-(2011/02/23(Wed) 16:41:16)
No57350 (TAKE さん) に返信
> 誰かdelegateの利点が自然に理解できるような
無茶ぶり? (^_^;)


> 例題をだしてもらえないでしょうか?
例題は思いつかないので、.NET 標準のデリゲートを使った話をしてみます。


たとえばデータの並びかえ。

幾つかの数値データを、
 List<int> foo = new List<int>();
に格納してあるとして…これを並び替えるには、
 foo.Sort();
とすれば良いですよね。List<T> ではなく配列なら、Array.Sort( 変数 ); です。


さて、これが数値型ではなく、自作クラス「社員」を格納していた場合はどうでしょう。
下記のようなケースです。

class 社員 {
    public ushort 社員番号;
    public string 氏名;
    public 社員(ushort 社員番号, string 氏名) {
        this.社員番号 = 社員番号;
        this.氏名 = 氏名;
    }
    public override string ToString() {
        return string.Format("{0,7} {1}", 社員番号, 氏名);
    }
}

//===================================
List<社員> foo = new List<社員>();
foo.Add(new 社員(400, "EEEE"));
foo.Add(new 社員(100, "BBBB"));
foo.Add(new 社員(300, "AAAA"));
foo.Add(new 社員(200, "CCCC"));
foo.Add(new 社員(500, "DDDD"));

Console.WriteLine("--- ソート前 ---");
foo.ForEach(Console.WriteLine);

Console.WriteLine("--- 氏名昇順 ---");
//
//  ここに、氏名昇順での並び替え処理を記述
//
foo.ForEach(Console.WriteLine);

Console.Write("Hit Any Key...");
Console.ReadKey();
//===================================


しかし Array クラスや List<T> は、データをどのように並び替えれば良いのか知りません。

そこで利用者側が「〜〜の順に並び替えてください」と指示をだし、Array や List<T> は
その指示に従ってデータを比較し、並び替えをおこなうという手順が必要になります。

そして、この比較方法を指定する方法として、IComparable<T> インターフェイスを
実装するという手法が用意されています。

  class 社員 : IComparable<社員> {
    int IComparable<社員>.CompareTo(社員 other) {
        return 社員番号.CompareTo(other.社員番号);
    }
    // 以下、先ほどと同様なので省略
  }

このようにしておくと、「foo.Sort();」で社員番号順に並び替えが行われます。
List<T> は、内部で上記のメソッドを呼び出して 社員インスタンスを比較し、
並び順を決定してくれます。

しかしこの方法は、並び順が一種類の場合は良いですが、複数の並び順を
切り替えられるように作るとなると、やや手間がかかってしまいます。

たとえば、氏名順に並び替えられるよう、
 return string.CompareOrdinal(a.氏名, b.氏名);
を返すように作りたい場合、IComparable.CompareTo を実装するときに、
なんらかの if 文分岐を用意してやる必要がありますし、新しい並び順を
定義したい場合、社員クラス自体に手を加えなければなりません。


そこで、並び替えのための「比較結果を返すデリゲート」Comparison<T> を使ってみます。
(似たようなものに、検索に使われる Predicate<T> デリゲートというものもあります)

たとえば、呼び出し側でこのようなメソッドを用意しておき、
  static int 氏名昇順(社員 a, 社員 b) {
     return string.CompareOrdinal(a.氏名, b.氏名);
  }
それを
  foo.Sort(new Comparison<社員>(氏名昇順));
のように指定すれば、氏名の昇順にソートさせることができます。
こうすれば、社員クラス自体には手を加えることなく、並び順を
利用者側で自由に定義できるようになります。

この場合、デリゲートの指定に匿名メソッドを用いることもできますし、
  Comparison<社員> 社員番号順 = delegate(社員 a, 社員 b) {
    return a.社員番号.CompareTo(b.社員番号);
  };
  foo.Sort(社員番号順);
その匿名メソッドを直接埋め込んで
  foo.Sort(delegate(社員 a, 社員 b) { return a.社員番号.CompareTo(b.社員番号); });
のように指定したり、さらにそれをラムダ式として
  foo.Sort((a, b) => a.社員番号.CompareTo(b.社員番号) );
と短縮表記していく事もできます。

# 最近だと、Linq で OrderBy 指定するという手もありますけれどね。

引用返信 編集キー/
■57365 / inTopicNo.3)  Re[2]: delegate
□投稿者/ TAKE (37回)-(2011/02/24(Thu) 09:10:21)
別件でちょっと忙しくなり
来週読ませていただきたいと思います。

長文のところ
ありがとうございます。

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -