本文へスキップ
BecomeCoder

C#オブジェクト指向コース · 第5章 オブジェクト指向の実践テクニック · レッスン37

IComparable と IEquatable の実装

ブラウザで完結

導入

自作クラスのリストを Sort() したら例外になった——それは「どちらが大きいか」のルールを型が持っていないからです。IComparable<T> は並べ替えの順序を、IEquatable<T> は等しさの判定を、型自身に持たせるインターフェースです。

図解

classDiagram
    class IComparable~T~ {
        +CompareTo(T other) int
    }
    class Money {
        +int Yen
        +CompareTo(Money other) int
    }
    IComparable~T~ <|.. Money

サンプル

var prices = new List<Money>
{
    new Money(300), new Money(100), new Money(200)
};
prices.Sort();   // IComparable のルールで並ぶ
Console.WriteLine(string.Join(",", prices.Select(m => m.Yen)));  // 100,200,300

class Money : IComparable<Money>
{
    public int Yen { get; }
    public Money(int yen) => Yen = yen;

    // 負=自分が小さい / 0=同じ / 正=自分が大きい
    public int CompareTo(Money? other) => Yen.CompareTo(other!.Yen);
}
  • IComparable<T>CompareTo が「並べ替えの順序」を定義する(Sort/OrderBy が使う)
  • IEquatable<T>Equals が「等しさ」を定義する(Contains などが使う)
  • 数値・文字列など標準型はこれらを最初から実装している

やってみよう

CompareTo の中を other!.Yen.CompareTo(Yen) にひっくり返すと降順になります。並び順が反転することを確かめましょう。

演習

var items = new List<Box> { new Box(3), new Box(1), new Box(2) };
items.Sort();
Console.WriteLine(string.Join(",", items.Select(b => b.Size)));   // 1,2,3

// TODO: Size の昇順で比較する IComparable<Box> を実装した Box を定義してください
___
  • 期待される出力: 1,2,3
ヒント1を見る

class Box : IComparable<Box> { public int Size { get; } public Box(int s) => Size = s; public int CompareTo(Box? other) => Size.CompareTo(other!.Size); }

ヒント2を見る

昇順は「自分の値 .CompareTo( 相手の値 )」の向きです

まとめ

  • IComparable<T> は並べ替えの順序を型に持たせる(Sort/OrderBy
  • IEquatable<T> は等しさの判定を型に持たせる
  • CompareTo の戻り値は 負/0/正 で大小を表す

次回: 親のメンバーを「隠す」new修飾子と、親を呼ぶ base です。

実際に動かしてみよう

本文のサンプルや演習のコードは、コードブロック右上の「コピー」ボタンでコピーして、下のエディタに貼り付ければそのまま実行できます。

C# — ブラウザ内で実行

ブラウザ内でC#を動かす環境を読み込みます(初回のみ数秒)。
スクロールして表示された時点でも自動で読み込まれます。