與C#定義了相等性比較規範同樣,C#也定義了排序比較規範,以肯定一個對象與另外一個對象的前後順序。排序規範以下html
當須要實現排序算法時,使用IComparable接口。在下面的例子中,Array.Sort靜態方法能夠調用,是由於System.String類實現了IComparable接口。算法
string[] colors={"Green", "Red", "Blue"}; Array.Sort(colors) foreach(string c in colors) Console.Write(c+ " ");
而<和>運算符比較特殊,由於他們通常用於比較數字類型。由於大於和小於運算符會被靜態地解析,所以它們「產生」出高效的代碼,適用於複雜計算的場景。ide
.NET Framework還提供了插件式的排序協議--IComparer接口。IComparable接口與IComparer接口的差異相似與IEquatable和IEqualityComparer接口 (關於IEqutable接口和IEqualityComparer接口,請參考C#相等性:http://www.cnblogs.com/yang_sy/p/3582946.html)this
IComparable接口的定義以下spa
public interface IComparable int CompareTo(Object obj); } public interface IComparable<in T> { int CompareTo(T other); }
這兩個接口定義了相同的功能。對於值類型,IComparable<T>接口效率高於ICompare接口。上面的兩個接口的CompareTo方法都按照下面的方式運行:插件
咱們來看下面的示例代碼:code
IList<Staff> staffs = new List<Staff> { new Staff{FirstName="AAA", Title="Manager", Dept="Sale"}, new Staff{FirstName="BBB", Title="Accountant", Dept="Finance"}, new Staff{FirstName="CCC", Title="Accountant", Dept="Finance"}, }; Console.WriteLine("BBB".CompareTo(staffs[0].FirstName)); // 1 Console.WriteLine("BBB".CompareTo(staffs[1].FirstName)); // 0 Console.WriteLine("BBB".CompareTo(staffs[2].FirstName)); // -1
C#的大部分基本類型都實現了IComparable接口和IComparable<T>接口。不少自定義類型一樣也實現了該接口,這樣便於排序。htm
IComarable與Equals對象
假設一個類型重寫了Equals方法並實現了IComparable接口。那麼你確定但願當Equals返回true時,CompareTo應當返回0。而Equals返回false時,CompareTo能夠返回任何值。blog
換句話說,相等性比對比性更嚴格;反之則不會。所以,當CompareTo說「兩個對象相等」時,Equals會說「這兩個對象不必定相等」。一個很好的例子來自System.String類。String.Equals方法和==運算符使用序號排序規則比較字符串--也就是經過每一個字符的Unicode的值進行排序。而String.CompareTo方法,卻使用不那麼嚴格的基於文化區域(culture-dependent)進行比較。對於大多數計算機,字符ǖ和ṻ,Equals返回False,而CompareTo返回0
你能夠實現經過IComparer接口,從而完成特定的排序算法。自定義IComparer接口的實現,進一步加大了CompareTo和Equals方法之間的差別。好比不區分大小寫的字符串比較器,對於A和a,將返回0. 這也從反面印證了,ComparTo方法不如Equals方法嚴格。
一些類型,定義了<和>運算符,好比:
bool after2010 = DateTime.Now > new DateTime(2010, 1, 1); Console.WriteLine(after2010);
當實現<和>運算符以後,你須要保證<和>運算符與IComparable接口保持一致。這也是.NET Framework的標準。
一樣地,當一個類型重載了<和>運算符,那麼也要求實現IComparable接口,而反之則不須要。實際上,大多數.NET類型實現了IComparable接口,並無重載<和>運算符。這(排序比較)與相等性比較不同:
通常地,只有在下面的情形中,才須要重載<運算符和>運算符:
System.Stirng類型不知足最後一條,所以string不支持>操做和<操做。所以 「beck」 > 「Anne」,編譯時會拋出錯誤。
下面的實例代碼中,結構Note表示一個音樂的註釋,它實現了IComparable接口,還重載了<運算符和>運算符。爲了實例的完整性,咱們還重寫了Equals和GetHashCode方法,以及重載了==和!=運算符,經過這個例子,你能夠全面的瞭解排序比較。
internal struct Note : IComparable, IComparable<Note>, IEquatable<Note> { private int semitonesFromA; public int SemitonesFromA { get { return semitonesFromA; } } public Note(int semitonesFromA) { this.semitonesFromA = semitonesFromA; } // generic IComparable<T> public int CompareTo(Note other) { if (Equals(other)) return 0; return SemitonesFromA.CompareTo(other.SemitonesFromA); } // non-generic IComaparable public int IComparable.CompareTo(object other) { if (!(other is Note)) throw new InvalidOperationException("CompareTo: Not a note"); return CompareTo((Note)other); } public static bool operator <(Note n1, Note n2) { return n1.CompareTo(n2) < 0; } public static bool operator >(Note n1, Note n2) { return n1.CompareTo(n2) > 0; } // for IEquatable public bool Equals(Note other) { return this.SemitonesFromA == other.SemitonesFromA; } // override Object.Equals public override bool Equals(object other) { if (!(other is Note)) throw new InvalidOperationException("CompareTo: Not a note"); return Equals((Note)other); } public override int GetHashCode() { return SemitonesFromA.GetHashCode(); } public static bool operator ==(Note n1, Note n2) { return n1.Equals(n2); } public static bool operator !=(Note n1, Note n2) { return !(n1 == n2); } }