はじめに
今回はIComparable
インターフェイスについての記事になります!
C#でたびたび登場する主要インターフェイスであるIComparable
・IComparable<T>
ですが、これによってオブジェクト同士の比較が保証することができます。
詳しくみていきましょう。
IComparableインターフェイスとは
IComparableインターフェイス
を実装することで比較を可能にするメソッドを提供します。
具体的に書くとIComparable
を実装しているとCompareToメソッド
を定義しなければなりません。
using System.Runtime.InteropServices; [ComVisible (true)] public interface IComparable { int CompareTo (object obj); }
public interface IComparable<in T> { int CompareTo (T other); }
IComparable
とIComparable<T>
は二つとも似たインターフェイスですが、定義からみても機能的には大差ありません。
ただジェネリックの方はCompareToメソッド
のとれる引数が制限されます。
その代わりにジェネリック版の方は処理が少し早いらしく、基本はこちらが推奨されているようです。
加えてCompareToメソッド
の返り値は以下のように定義されています(自前のときはしなければなりません)。
- オブジェクトが引数で与えられたオブジェクトより前にあるなら0未満
- オブジェクトが引数で与えられたオブジェクトと同じ位置なら0
- オブジェクトが引数で与えられたオブジェクトより後にあるなら0より大きい
private void Start() { int a = 1; Debug.Log(a.CompareTo(2)); // -1 Debug.Log(a.CompareTo(1)); // 0 Debug.Log(a.CompareTo(0)); // 1 }
使った例
3つの値の中央値を求めるコードを書いてみました。
このIComparable<T>
を用いることで、int
でもfloat
でも中央値を求めることができます。
using System; using UnityEngine; public class Test : MonoBehaviour { private void Start() { int a = 10; int b = 5; int c = 15; var median = Median<int>(a, b, c); Debug.Log(median); // 10 } /// <summary> /// 3つの値の中央値を求める。 /// </summary> static T Median<T>(T a, T b, T c) where T : IComparable<T> { if (a.CompareTo(b) > 0) Swap(ref a, ref b); if (a.CompareTo(c) > 0) Swap(ref a, ref c); if (b.CompareTo(c) > 0) Swap(ref b, ref c); return b; } /// <summary> /// 参照を入れ替える(値型だと変数のコピーになってしまうため) /// </summary> private static void Swap<T>(ref T x, ref T y) where T : IComparable<T> { var tmp = x; x = y; y = tmp; } }
自作クラス
次に自作クラスにIComparable<T>
を実装してみましょう。
今回は「文字列の長さが長ければ大きい」という仕組みを作ってみます。
public class MyString : IComparable<MyString> { public string Text { get; } public MyString(string text) => Text = text; public int CompareTo(MyString other) { if(other.Text.Length > Text.Length) { return -1; } else if(other.Text.Length < Text.Length) { return 1; } else { return 0; } } }
これを使ってみるとこんな感じ。
public class Test : MonoBehaviour { private void Start() { List<MyString> list = new List<MyString>(); list.Add(new MyString("hello")); list.Add(new MyString("a")); list.Add(new MyString("I'm fine. Thank you.")); // 昇順にソート list.Sort(); Debug.Log(list[0].Text); // a } }
さいごに
Array.Sort
やArrayList.Sort
,List
などのメソッドで自動的に呼び出されるらしく、自前で実装すればList<T>.Sort()
も勝手に使えるようになります。
特にアルゴリズム関連では重宝しそうなインターフェイスなので、是非うまく活用してみてください。
ではまた。