公司最近进了个实习生,天天下班前我都会花一些时间来解答一下实习生的一些疑问。今天问起了关于集合排序方法Sort的一些疑问,这让我一下回到本身刚刚入行的时候。那个时候也遇到了集合排序的问题,为发现接口IComparable和ICompare的妙处而兴奋,还在公司的内部分享会上分享了如何使用它们来排序。如今通过多年的开发实践以及学习,对于同一个问题又有了更加深刻的理解。html
实习生先是问了这个问题, 其实这个问题, 很是容易解答.
先来看看IEnumerable接口的定义:函数
public interface IEnumerable { IEnumerator GetEnumerator(); }
这个接口很是简单,主要就是一个方法GetEnumerator,用来返回一个IEnumerator对象。
继续深刻下去,IEnumerator接口的定义以下:学习
public interface IEnumerator { bool MoveNext(); void Reset(); object Current { get; } }
上面的IEnumerator接口定义的属性和方法,只有一个目的,就是实现如何遍历。下面具体解释一下:spa
到这里,为何foreach可以遍历集合对象的缘由就是由于集合对象都实现了IEnumerable接口,提供了具体的实现来遍历集合对象。设计
集合类型,都有Sort()排序方法,这个函数的一个重载版本中,须要提供一个IComparer类型的接口。为何须要使用这个接口呢?这个和排序有什么关系?
想想,实现排序必须的是什么?必须的是可以比较大小。对于int, string这种.Net内部类型,自己已经支持了IComparer, 也就是能够比较大小了。可是对于咱们本身定义的类型,使用Sort方法是没法排序的,由于程序不知道咱们对于自定义对象的排序规则, 这个时候就可使用IComparable、IComparer.3d
下面举一个实际的例子, 这里咱们自定义了一个类Car, 而后对Car的集合进行排序.code
public class Car { public string Name { get; set; } public int Year { get; set; } public int Seats { get; set; } }
假如咱们直接调用Sort方法, 就会悲剧抛出InvalidOperationException异常htm
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()方法,就可以获得排序结果:blog
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属性不一样:
还能够实现一个根据Car的属性Seats排序的IComparer. 因此使用IComparer更加的灵活
Collection中的Sort()方法很好地遵循了开放封闭原则,既很好地完成了排序的功能,同时又开放出了入口,让你能够为排序自定义规则。
下面是我我的的一些我的理解:
一个类应该作本身擅长的事情和核心的事情(单一职责),把不擅长的交给别人。可是这个”别人“是否是任何人均可以呢?固然不是,为了更好的限定别人,咱们使用了接口限定。
当一个类依赖于抽象(也就是接口),那么这个类的适用范围就更加广,就可以更加超脱。老子一句”道可道,很是道;名可名,很是名”,正是没有具体化,因此能够解释万物。
更多的面向对象设计原则,参照http://www.360doc.com/content/11/0521/00/3554006_118258005.shtml
最后附上本文相关源代码: SortDemo