torutkのブログ

ソフトウェア・エンジニアのブログ

比較(IComparableとIComparerとComparison)

Effective C# 2nd Edition, Item 31 "Implement Ordering Relations with IComparable and IComparer"を読んで、さらにComparisonが登場して、「うむむ」。
英語ネイティブでないプログラマーにはいじめとも思われる.NET Frameworkライブラリです。

まず、自前の型を作成するとき、コレクションに入れてソートするならIComparableを実装します(その型の自然なソート)。ここまでは読んですぐに理解できました。次に、自然なソートとは別のソートを行いたいときに、Comparisonデリゲートや、IComparer実装型のオブジェクトを用意する例が出てきますが、こちらは難解でした。

最初にComparisonの例ですが、

public struct Customer : IComparable<T>, IComparable
{
    private readonly string name;
    private double revenue;
     : (中略)
    public static Comparison<Customer> CompareByRevenue
    {
        get {
            return (left, right) =>
                left.revenue.CompareTo(right.revenue);
        }
    }
}

と、いきなり難解なコードが出てきました。読みほぐすと、

  • 静的(クラス)プロパティCompareByRevenueを定義
  • このプロパティの型は、デリゲート型Comparisonに型パラメータCustomerを指定
  • このプロパティはgetのみ定義
  • getでは、ラムダ式を返却

ということのようです。

続くIComparerの例は、(コードの順番入れ換え有)

    private class RevenueComparer : IComparer<Customer>
    {
        int IComparer<Customer>.Compare(Customer left, Customer right)
        {
            return left.revenue.CompareTo(right.revenue);
        }
    }
    private static RevenueComparer revComp = null;
    public static IComparer<Customer> RevenueCompare
    {
        get
        {
            if (revComp == null)
                revComp = new RevenueComparer();
            return revComp;
        }
    }
  • IComparerに型パラメータCustomerを適用し、これを実装する内部クラスRevenueComparerを定義
  • IComparerに型パラメータCustomerを適用し、この型の静的プロパティRevenueCompareを定義

かなりに難解です。また、なぜにComparisonとIComparerと複数の手段があるのだろうか。C#にはなかなか馴染めそうにありません。