2013年4月25日木曜日

Comparison デリゲートを利用した IComparer の実装クラス

訳のわからないタイトル。


事の起こりは、ジェネリックの「SortedDictionary」クラスを使おうと思ったこと。

デフォルトの比較ルールだと、希望する順番にソートされないので、比較関数を置き変えたかった。そのためにはどうするのか?MSDNを引いてみると、



SortedDictionaryのコンストラクタのオーバーロードを確認しても、IComparer<TKey>を指定するものはあっても、Comparison<TKey>を指定できるものはない。えー?このためにクラス一個作んないとダメってことかい?めんどくせ。

List<T>とかのSortメソッドには、Comparison<T>もIComparer<T>もどっちも引き渡せるようになっているのに…。.net 2.0の時代ならいざ知らず…、ちょっと片手落ちじゃないすか?というか、手を入れ損なったのかなぁ。

ま、無いものはしょうがない。とはいえ、クラスを作るにしても似たようなものを何度も作りたくはない。なので、『Comparison<T> デリゲートを利用した IComparer<T> の実装クラス』を作り、汎用的に使いまわせるようにしようと考えた次第。

しかし、ここで悩んだのはそのクラス名。汎用的なIComparer実装クラスなので、「Comparer」クラスにしたかったのだけど、「System.Coolection.Generic.Comparer」クラスが既に存在しているので却下。

悩んだ挙句、「ComparisonComparer<T>」にしました。頭痛が痛いような名前。でもまぁ、名は体を表していることには違いないし、なによりIntellisenceで「Compar...」でリストアップされるので、まぁ、使い勝手は悪くないんじゃないかと思う。

およそ実装はこんな感じ。

class ComparisonComparer<T> : IComparer<T>
{
  private Comparison<T> comparison;

  public ComparisonComparer(Comparison<T> comparison)
  {
    this.comparison = comparison;
  }

  public int Compare(T p1, T p2)
  {
    return comparison(p1, p2);
  }
}

念のため、ジェネリックじゃないIComparerも実装しておいたほうがいいかも。そして、こう使うと。

var dic = new SortedDictionary<string, int>(
    new ComparisonComparer<string>((p1, p2) => string.Compare(p1, p2)));

正直、それほど使い道があるわけじゃない(ざっと見た限り、SortedListやSortedSetではIComparer<T>が必要なので、使い道はありそうだけど、それくらい…)。だけど、いちいちクラス一個作るよりはいいでしょ。

0 件のコメント:

コメントを投稿