.Net Collection的一些理解——記錄一次向實習生的答疑


公司最近進了個實習生,每天下班前我都會花一些時間來解答一下實習生的一些疑問。今天問起了關於集合排序方法Sort的一些疑問,這讓我一下回到自己剛剛入行的時候。那個時候也遇到了集合排序的問題,為發現接口IComparableICompare的妙處而興奮,還在公司的內部分享會上分享了如何使用它們來排序。現在經過多年的開發實踐以及學習,對於同一個問題又有了更加深入的理解。

一. 為什么說”實現了IEnumerable接口才能遍歷”

實習生先是問了這個問題, 其實這個問題, 非常容易解答.
先來看看IEnumerable接口的定義:

public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

這個接口非常簡單,主要就是一個方法GetEnumerator,用來返回一個IEnumerator對象。
繼續深入下去,IEnumerator接口的定義如下:

public interface IEnumerator
{
   bool MoveNext();
      void Reset();
     object Current {  get; }
}

上面的IEnumerator接口定義的屬性和方法,只有一個目的,就是實現如何遍歷。下面具體解釋一下:

  • Current屬性, 用來返回當前集合項的值
  • MoveNext方法, 移動到集合對象的下一項,如果有下一項,就返回true, 如果沒有,就返回false.
  • Reset(), 重置然后可以重頭訪問集合

到這里,為什么foreach能夠遍歷集合對象的原因就是因為集合對象都實現了IEnumerable接口,提供了具體的實現來遍歷集合對象。

二. Sort()方法以及IComparable、IComparer接口

集合類型,都有Sort()排序方法,這個函數的一個重載版本中,需要提供一個IComparer類型的接口。為什么需要使用這個接口呢?這個和排序有什么關系?
想一想,實現排序必須的是什么?必須的是能夠比較大小。對於int, string這種.Net內部類型,本身已經支持了IComparer, 也就是可以比較大小了。但是對於我們自己定義的類型,使用Sort方法是無法排序的,因為程序不知道我們對於自定義對象的排序規則, 這個時候就可以使用IComparableIComparer.

下面舉一個實際的例子, 這里我們自定義了一個類Car, 然后對Car的集合進行排序.

public class Car
{
       public string Name { get; set; }
       public int Year { get; set; }
       public int Seats { get; set; }
}

假如我們直接調用Sort方法, 就會悲劇拋出InvalidOperationException異常

image 

2.1 IComparable接口

IComparable 接口提供了比較某個特定類型對象的方法. 這里來說, 我們要讓Car實現IComparable 接口來達到比較Car對象的目的,從而實現排序。實現IComparable接口, 就必須實現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對象實現了IComparable接口,按照Name字符串屬性來比較. 直接運行Sort()方法,就能夠得到排序結果:

image

2.2 IComparer接口

IComparer接口可以提供更加豐富和靈活的排序功能。 比如, 你可能需要在不同的場合,根據不同的屬性來排序.
下面就來實現一個根據Car的Year屬性來排序, 首先創建類CarYearComparer來對Car進行比較,比較是根據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;
       }
}

在調用Sort方法排序的時候,需要指定使用的IComparer實現:

cars.Sort(new CarYearComparer());

得到的排序結果和上面的根據Name屬性不同:

image

還可以實現一個根據Car的屬性Seats排序的IComparer. 所以使用IComparer更加的靈活

3. 面向對象設計思想

Collection中的Sort()方法很好地遵循了開放封閉原則,既很好地完成了排序的功能,同時又開放出了入口,讓你可以為排序自定義規則。

下面是我個人的一些個人理解:
一個類應該做自己擅長的事情和核心的事情(單一職責),把不擅長的交給別人。但是這個”別人“是不是任何人都可以呢?當然不是,為了更好的限定別人,我們使用了接口限定。
當一個類依賴於抽象(也就是接口),那么這個類的適用范圍就更加廣,就能夠更加超脫。老子一句”道可道,非常道;名可名,非常名”,正是沒有具體化,所以可以解釋萬物。

更多的面向對象設計原則,參照http://www.360doc.com/content/11/0521/00/3554006_118258005.shtml

最后附上本文相關源代碼: SortDemo


免責聲明!

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



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