與C#定義了相等性比較規(guī)范一樣,C#也定義了排序比較規(guī)范,以確定一個(gè)對(duì)象與另一個(gè)對(duì)象的先后順序。排序規(guī)范如下
當(dāng)需要實(shí)現(xiàn)排序算法時(shí),使用IComparable接口。在下面的例子中,Array.Sort靜態(tài)方法可以調(diào)用,是因?yàn)镾ystem.String類(lèi)實(shí)現(xiàn)了IComparable接口。
string[] colors={"Green", "Red", "Blue"};Array.Sort(colors)foreach(string c in colors) Console.Write(c+ " ");而<和>運(yùn)算符比較特殊,因?yàn)樗麄円话阌糜诒容^數(shù)字類(lèi)型。因?yàn)榇笥诤托∮谶\(yùn)算符會(huì)被靜態(tài)地解析,因此它們“產(chǎn)生”出高效的代碼,適用于復(fù)雜計(jì)算的場(chǎng)景。
.NET Framework還提供了插件式的排序協(xié)議--IComparer接口。IComparable接口與IComparer接口的差別類(lèi)似與IEquatable和IEqualityComparer接口 (關(guān)于IEqutable接口和IEqualityComparer接口,請(qǐng)參考C#相等性:http://www.survivalescaperooms.com/yang_sy/p/3582946.html)
IComparable接口的定義如下
public interface IComparable int CompareTo(Object obj);}public interface IComparable<in T>{ int CompareTo(T other);}這兩個(gè)接口定義了相同的功能。對(duì)于值類(lèi)型,IComparable<T>接口效率高于ICompare接口。上面的兩個(gè)接口的CompareTo方法都按照下面的方式運(yùn)行:
我們來(lái)看下面的示例代碼:
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)); // 1Console.WriteLine("BBB".CompareTo(staffs[1].FirstName)); // 0Console.WriteLine("BBB".CompareTo(staffs[2].FirstName)); // -1C#的大部分基本類(lèi)型都實(shí)現(xiàn)了IComparable接口和IComparable<T>接口。很多自定義類(lèi)型同樣也實(shí)現(xiàn)了該接口,這樣便于排序。
IComarable與Equals
假設(shè)一個(gè)類(lèi)型重寫(xiě)了Equals方法并實(shí)現(xiàn)了IComparable接口。那么你肯定希望當(dāng)Equals返回true時(shí),CompareTo應(yīng)當(dāng)返回0。而Equals返回false時(shí),CompareTo可以返回任何值。
換句話(huà)說(shuō),相等性比對(duì)比性更嚴(yán)格;反之則不會(huì)。因此,當(dāng)CompareTo說(shuō)“兩個(gè)對(duì)象相等”時(shí),Equals會(huì)說(shuō)“這兩個(gè)對(duì)象不一定相等”。一個(gè)很好的例子來(lái)自System.String類(lèi)。String.Equals方法和==運(yùn)算符使用序號(hào)排序規(guī)則比較字符串--也就是通過(guò)每個(gè)字符的Unicode的值進(jìn)行排序。而String.CompareTo方法,卻使用不那么嚴(yán)格的基于文化區(qū)域(culture-dependent)進(jìn)行比較。對(duì)于大多數(shù)計(jì)算機(jī),字符ǖ和?,Equals返回False,而CompareTo返回0
你可以實(shí)現(xiàn)通過(guò)IComparer接口,從而完成特定的排序算法。自定義IComparer接口的實(shí)現(xiàn),進(jìn)一步加大了CompareTo和Equals方法之間的差異。比如不區(qū)分大小寫(xiě)的字符串比較器,對(duì)于A和a,將返回0. 這也從反面印證了,ComparTo方法不如Equals方法嚴(yán)格。
一些類(lèi)型,定義了<和>運(yùn)算符,比如:
bool after2010 = DateTime.Now > new DateTime(2010, 1, 1);Console.WriteLine(after2010);
當(dāng)實(shí)現(xiàn)<和>運(yùn)算符之后,你需要保證<和>運(yùn)算符與IComparable接口保持一致。這也是.NET Framework的標(biāo)準(zhǔn)。
同樣地,當(dāng)一個(gè)類(lèi)型重載了<和>運(yùn)算符,那么也要求實(shí)現(xiàn)IComparable接口,而反之則不需要。實(shí)際上,大多數(shù).NET類(lèi)型實(shí)現(xiàn)了IComparable接口,并沒(méi)有重載<和>運(yùn)算符。這(排序比較)與相等性比較不一樣:
一般地,只有在下面的情形中,才需要重載<運(yùn)算符和>運(yùn)算符:
System.Stirng類(lèi)型不滿(mǎn)足最后一條,因此string不支持>操作和<操作。因此 “beck” > “Anne”,編譯時(shí)會(huì)拋出錯(cuò)誤。
下面的實(shí)例代碼中,結(jié)構(gòu)Note表示一個(gè)音樂(lè)的注釋?zhuān)鼘?shí)現(xiàn)了IComparable接口,還重載了<運(yùn)算符和>運(yùn)算符。為了實(shí)例的完整性,我們還重寫(xiě)了Equals和GetHashCode方法,以及重載了==和!=運(yùn)算符,通過(guò)這個(gè)例子,你可以全面的了解排序比較。
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); }}新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注