C# IComparable


IComparable是C#和.NET中確認對象之間相對順序的標准協議之一。

准確的來說IComparable包括IComparable和IComparable<T>兩個接口。

而另外一種則是我們運用的非常之多的“<”和“>”運算符。

IComparablede的定義方式如下:

 public interface IComparable
    {
        int CompareTo(object othor);
    }
    public interface IComparable<in T>
    {
        int CompareTo(T othor);
    }

這兩個接口實現了相同的功能。對於值類型,泛型安全的接口執行速度比非泛型要快。

它們的CompareTo方法按照如下的方式執行。

  • 如果a在b之后,則a.CompareTo(b)返回一個正數
  • 如果a和b的位置相同,a.CompareTo(b)返回0
  • 如果a在b之前,a.CompareTo(b)返回一個負數
                Console.WriteLine("A".CompareTo("B"));//-1
                Console.WriteLine("B".CompareTo("B"));//0
                Console.WriteLine("B".CompareTo("A"));//1

上面這個例子可以看出來String類型是有實現IComparable接口的,那不然怎么能使用這個方法。

那當我們自己在創建一個結構體想要提升它的比較效率的時候,我們自己也能通過IComparable來實現。

上代碼

  public struct Note : IComparable<Note>, IEquatable<Note>, IComparable
    {
        int _semitonesFromA;
        public int SemitonesFromA { get => _semitonesFromA; }

        public Note(int semitonesFromA)
        {
            _semitonesFromA = semitonesFromA;
        }
        /// <summary>
        /// 實現泛型接口
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public int CompareTo(Note other)
        {
            if (Equals(other)) return 0;
            return _semitonesFromA.CompareTo(other._semitonesFromA);
        }
        /// <summary>
        /// 實現非泛型接口
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        int IComparable.CompareTo(object obj)
        {
            if (!(obj is Note))
                throw new InvalidOperationException("不是Note");
            return CompareTo((Note)obj);
        }
        /*重載“<”和“>”運算符*/
        public static bool operator >(Note n1, Note n2) => n1.CompareTo(n2) > 0;
        public static bool operator <(Note n1, Note n2) => n1.CompareTo(n2) < 0;
        /// <summary>
        /// 實現IEquatable
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool Equals(Note other) => other._semitonesFromA == this._semitonesFromA;
        /// <summary>
        /// 重寫Equals
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (!(obj is Note)) return false;
            return Equals((Note)obj);
        }
        /// <summary>
        /// 重寫GetHashCode
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this._semitonesFromA.GetHashCode();
        }
        /*重載==和!=運算符*/
        public static bool operator ==(Note n1, Note n2) => n1.Equals(n1);
        public static bool operator !=(Note n1, Note n2) => !n1.Equals(n1);
    }

測試

                var note = new Note(9);
                var note2 = new Note(10);
                var note3 = new Note(11);
                Console.WriteLine(note2.CompareTo(note3));//-1
                Console.WriteLine(note2.CompareTo(note2));//0
                Console.WriteLine(note3.CompareTo(note));//1
                Console.WriteLine(note3 > note2);//true
                Console.WriteLine(note2 < note);//false

上面這個例子重載了IComparable接口並且重載了運算符“<”和“>”。同時還實現了IEquatable接口,詳情見我博客相等比較

這里就說說為啥要重載運算符“<”和“>”。

運算符“<”和“>”的是實現在功能上和IComparable接口時一致的。當然這是整個.NET Framework的標准做法。

我們的例子重載了運算符“<”和“>”,但實際情況下實現IComparable並不一定需要實現運算符“<”和“>”,但是如果重載運算符“<”和“>”那么就必須要實現IComparable。

對於這個必須,我的理解是運算符“<”和“>”的實現是必須要基於IComparable的。

那實現IComparable時,我們什么樣的情況下,需要實現運算符“<”和“>”呢。

  • 類型具有固有的“大於”和“小於”的概念(對於IComparable的更寬泛的“之前”和“之后”)
  • 這種比較只能用一種方式或在一個上下文下執行。
  • 比較的結果在各文化中保持不變。

所有的數值類型基本都實現了運算符“<”和“>”,因為數值類型都符合這三個條件。

System.String就不滿足最后一點bool ok="Back">"Anne"這句代碼就會報錯。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM