公司最近進了個實習生,每天下班前我都會花一些時間來解答一下實習生的一些疑問。今天問起了關(guān)于集合排序方法Sort的一些疑問,這讓我一下回到自己剛剛?cè)胄械臅r候。那個時候也遇到了集合排序的問題,為發(fā)現(xiàn)接口IComparable和ICompare的妙處而興奮,還在公司的內(nèi)部分享會上分享了如何使用它們來排序。現(xiàn)在經(jīng)過多年的開發(fā)實踐以及學(xué)習,對于同一個問題又有了更加深入的理解。
實習生先是問了這個問題, 其實這個問題, 非常容易解答.
先來看看IEnumerable接口的定義:
public interface IEnumerable{ IEnumerator GetEnumerator();}
這個接口非常簡單,主要就是一個方法GetEnumerator,用來返回一個IEnumerator對象。
繼續(xù)深入下去,IEnumerator接口的定義如下:
public interface IEnumerator{ bool MoveNext(); void Reset(); object Current { get; }}
上面的IEnumerator接口定義的屬性和方法,只有一個目的,就是實現(xiàn)如何遍歷。下面具體解釋一下:
到這里,為什么foreach能夠遍歷集合對象的原因就是因為集合對象都實現(xiàn)了IEnumerable接口,提供了具體的實現(xiàn)來遍歷集合對象。
集合類型,都有Sort()排序方法,這個函數(shù)的一個重載版本中,需要提供一個IComparer類型的接口。為什么需要使用這個接口呢?這個和排序有什么關(guān)系?
想一想,實現(xiàn)排序必須的是什么?必須的是能夠比較大小。對于int, string這種.Net內(nèi)部類型,本身已經(jīng)支持了IComparer, 也就是可以比較大小了。但是對于我們自己定義的類型,使用Sort方法是無法排序的,因為程序不知道我們對于自定義對象的排序規(guī)則, 這個時候就可以使用IComparable、IComparer.
下面舉一個實際的例子, 這里我們自定義了一個類Car, 然后對Car的集合進行排序.
public class Car{ public string Name { get; set; } public int Year { get; set; } public int Seats { get; set; }}
假如我們直接調(diào)用Sort方法, 就會悲劇拋出InvalidOperationException異常
IComparable 接口提供了比較某個特定類型對象的方法. 這里來說, 我們要讓Car實現(xiàn)IComparable 接口來達到比較Car對象的目的,從而實現(xiàn)排序。實現(xiàn)IComparable接口, 就必須實現(xiàn)CompareTo 方法, 具體如下:
public class Car: IComparable{ public string Name { get; set; } public int Year { get; set; } public int Seats { get; set; } public int CompareTo(object obj) { var car = (Car) obj; return String.CompareOrdinal(Name, car.Name); }}
上面我們的Car對象實現(xiàn)了IComparable接口,按照Name字符串屬性來比較. 直接運行Sort()方法,就能夠得到排序結(jié)果:

IComparer接口可以提供更加豐富和靈活的排序功能。 比如, 你可能需要在不同的場合,根據(jù)不同的屬性來排序.
下面就來實現(xiàn)一個根據(jù)Car的Year屬性來排序, 首先創(chuàng)建類CarYearComparer來對Car進行比較,比較是根據(jù)Year屬性
public class CarYearComparer: IComparer<Car>{ public int Compare(Car x, Car y) { if (x.Year > y.Year) return 1; if (x.Year < y.Year) return -1; return 0; }}
在調(diào)用Sort方法排序的時候,需要指定使用的IComparer實現(xiàn):
cars.Sort(new CarYearComparer());得到的排序結(jié)果和上面的根據(jù)Name屬性不同:

還可以實現(xiàn)一個根據(jù)Car的屬性Seats排序的IComparer. 所以使用IComparer更加的靈活
Collection中的Sort()方法很好地遵循了開放封閉原則,既很好地完成了排序的功能,同時又開放出了入口,讓你可以為排序自定義規(guī)則。
下面是我個人的一些個人理解:
一個類應(yīng)該做自己擅長的事情和核心的事情(單一職責),把不擅長的交給別人。但是這個”別人“是不是任何人都可以呢?當然不是,為了更好的限定別人,我們使用了接口限定。
當一個類依賴于抽象(也就是接口),那么這個類的適用范圍就更加廣,就能夠更加超脫。老子一句”道可道,非常道;名可名,非常名”,正是沒有具體化,所以可以解釋萬物。
更多的面向?qū)ο笤O(shè)計原則,參照http://www.360doc.com/content/11/0521/00/3554006_118258005.shtml
最后附上本文相關(guān)源代碼: SortDemo
新聞熱點
疑難解答