(1) C#のIComparableの実装方法+IComparerとの違いについて
 (1-1) IComparableの概要とIComparableとの違い
 (1-2) STEP0:比較をするクラスの定義
 (1-3) STEP1:IComparableインターフェイスの実装
 (1-4) STEP2:Compareメソッドの実装
 (1-5) STEP3:ソートの実行
 (1-6) サンプルプログラム
(1) C#のIComparableの実装方法+IComparerとの違いについて
(1-1) IComparableの概要とIComparableとの違い
「IComparable」は、オブジェクト同士の比較を行うためのメソッドを公開したインターフェイスです。似た名前のインターフェイスで「IComparer」がありますが、違いとして「IComparable」は自分と同じ型のオブジェクトを受け取って比較する(自分と相手の比較)なのに対して、「IComparer」は同じ型の異なるオブジェクトを比較する(二者の比較)という点で異なります。
もう少しイメージが湧きやすいように、プログラムの骨組みで比較すると、次のようなイメージです。
(図111)IComparableは「自クラス」と同型の「相手クラス」との比較

(図112)IComparerは「2つの同型の異なるクラス」同士の比較

(1-2) STEP0:比較をするクラスの定義
まずはベースとなる、比較を行いたいクラスを作ります。
次の例は「Big4Players」という、男子テニスの「Big4」と呼ばれる選手(フェデラー、ナダル、ジョコビッチ、マレー)の「名前」(Name)と「グランドスラム優勝回数」(GrandSlamWin)と保持するためのクラスです(テニスネタでスミマセン・・💦)。
(STEP0)
    // STEP0:比較をするクラスの定義
    class Big4Players
    {
        // メンバ変数
        public string Name { get; set; }
        public int GrandSlamWin { get; set; }
    }
(参考)
「{ get; set; }」は「プロパティ」と呼ばれ、メンバ変数のゲッター(取得)、セッター(更新)のメソッドを定義しています。
(1-3) STEP1:IComparableインターフェイスの実装
次に、定義したクラスが「IComparable」インターフェイスを実装するように改修します。
(STEP1)
    // STEP0:比較をするクラスの定義
    // STEP1:IComparableインターフェイスの実装
    class Big4Players : IComparable<Big4Players>
    {
        // メンバ変数
        public string Name { get; set; }
        public int GrandSlamWin { get; set; }
    }
(1-4) STEP2:CompareToメソッドの実装
次はいよいよ「CompareTo」メソッドを実装します。
ちなみにIComparerの時の比較メソッドは「Compare」という名前でしたが、今回は「自分」と「相手」を比較するので「CompareTo」(~と比べる)の方が確かに名前としてしっくり来ます。
今回は優勝回数が多い順に並べるので降順ソートで実装しています。
(STEP2)
    // STEP0:比較をするクラスの定義
    // STEP1:IComparableインターフェイスの実装
    class Big4Players : IComparable
    {
        // メンバ変数
        public string Name { get; set; }
        public int GrandSlamWin { get; set; }
        // STEP2:CompareToメソッドの実装
        public int CompareTo(Big4Players other)
        {
            // 降順にソートしたいので、this(自分) < other(相手) に1を割り当て
            if (this.GrandSlamWin < other.GrandSlamWin)
            {
                return 1;
            }
            // 降順にソートしたいので、this(自分) > other(相手) に-1を割り当て
            else if (this.GrandSlamWin > other.GrandSlamWin)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }
        // コンソール出力用のメソッド
        public override string ToString()
        {
            return $"{this.Name} {this.GrandSlamWin}";
        }
    }
(1-5) STEP3:ソートの実行
ここまで来たら実際にソートしたいListを定義して、要素を追加してSort()メソッドを実行する事でソートが行えます。Sortメソッドの引数には先ほど定義したBig4Comparerクラスのインスタンスを与えます。
    class Program
    {
        static void Main(string[] args)
        {
            // var(暗黙型)でBig4Players2のリストを定義
            var big4 = new List<Big4Players>();
            // リストに要素を追加
            big4.Add(new Big4Players() { Name = "Roger Federer", GrandSlamWin = 20 });
            big4.Add(new Big4Players() { Name = "Rafale Nadal", GrandSlamWin = 20 });
            big4.Add(new Big4Players() { Name = "Novak Djokovic", GrandSlamWin = 17 });
            big4.Add(new Big4Players() { Name = "Andy Murray", GrandSlamWin = 3 });
            // ソートの実行(内部的にCompareToメソッドが使われる)
            big4.Sort();
            // コンソール出力
            big4.ForEach(big4player => Console.WriteLine(big4player));
        }
    }
(1-6) サンプルプログラム
上記STEP0~STEP3までを繋げて、main文などを追記して実行可能にしたものを掲載します。
プログラム中で登場するvar(暗黙型)については別記事でも説明しているため、興味ある方は併せてご覧いただけたらと思います。
参考①:C#のvarの使いどころは?初めての方に向けてサンプルプログラムを使ってご紹介
参考②:C#のvarとは?型を調べる方法や制約事項についてもご紹介
(サンプルプログラム)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IComparerTest
{
    // STEP0:比較をするクラスの定義
    // STEP1:IComparableインターフェイスの実装
    class Big4Players : IComparable<Big4Players>
    {
        // メンバ変数
        public string Name { get; set; }
        public int GrandSlamWin { get; set; }
        // STEP2:CompareToメソッドの実装
        public int CompareTo(Big4Players other)
        {
            // 降順にソートしたいので、this(自分) < other(相手) に1を割り当て
            if (this.GrandSlamWin < other.GrandSlamWin)
            {
                return 1;
            }
            // 降順にソートしたいので、this(自分) > other(相手) に-1を割り当て
            else if (this.GrandSlamWin > other.GrandSlamWin)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }
        // コンソール出力用のメソッド
        public override string ToString()
        {
            return $"{this.Name} {this.GrandSlamWin}";
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            // var(暗黙型)でBig4Players2のリストを定義
            var big4 = new List<Big4Players>();
            // リストに要素を追加
            big4.Add(new Big4Players() { Name = "Roger Federer", GrandSlamWin = 20 });
            big4.Add(new Big4Players() { Name = "Rafale Nadal", GrandSlamWin = 20 });
            big4.Add(new Big4Players() { Name = "Novak Djokovic", GrandSlamWin = 17 });
            big4.Add(new Big4Players() { Name = "Andy Murray", GrandSlamWin = 3 });
            // ソートの実行(内部的にCompareToメソッドが使われる)
            big4.Sort();
            // コンソール出力
            big4.ForEach(big4player => Console.WriteLine(big4player));
        }
    }
}
(図161)実行結果
狙った通り降順にソートされています(20⇒20⇒17⇒3)

 
											 
											 
											 
											