对于 飞林沙的<把Array说透>的扩展
今天看到 飞林沙同学的两个帖子
把Array说透和把Array说透序一这两个帖子都是从很底层的原理以及来说Array数组,看了让人很受启发,所以我想写一篇从FCL的角度来阐述数组的文章,权当抛砖引玉,高手请飘走....
System.Array
地球人都知道,所有的数组都是隐式的派生于这个基类。在MSDN里可以发现System.Array的原型是:
1 [SerializableAttribute]
2 [ComVisibleAttribute(true)]
3 public abstract class Array : ICloneable,
4 IList, ICollection, IEnumerable
5
2 [ComVisibleAttribute(true)]
3 public abstract class Array : ICloneable,
4 IList, ICollection, IEnumerable
5
而几乎所有Array所具备的功能都是实现这几个接口.下面说说这几个接口之间的关系。
IEnumerable
这个接口就是传说中的祖宗,是IList和ICollection接口的父接口.这个接口只有一个方法.GetEnumerator(),这也是.net FCL对实现迭代器模式的接口。在.net中,所有实现了IEnumerable接口的类才能用foreach关键字进行遍历.
IEnumberator
实现IEnumberator接口的类是IEnumerable接口GetEnumerator()方法返回的类型,表示是集合中当前的元素,实现IEnumberator接口需要实现两个方法和一个属性
IEnumberator内部有MoveNext()方法和Reset()方法,从名字不难看出,前者的用处是返回集合中下一个需要被遍历的元素,而Reset()方法让当前的Enumberator回到集合中的第一个元素.
IEnumberator还有Current属性,返回集合中Enumberator中当前的元素.
下面通过MSDN中的代码来对这两个接口进行说明:
Msdn中对IEunmerable接口的代码演示
ICollection
这个接口直接继承自IEnumerable接口,这个接口是System.Collections命名空间的基本接口,从这个接口开始就有一些数组特性了. 实现ICollection接口需要实现4个方法(包括从IEnumerable继承来的一个方法),和一个属性
ICollection所具有的3个方法是AddAt,AddItem,Item这三个方法,AddAt和AddItem方法均是添加一个元素到集合,AddAt可以选择集合中的任何位置进行插入,而AddItem方法默认将元素插入队尾。
ICollection的属性是表示当前集合大小的Count属性.
IList
IList又直接继承与ICollection接口和IEnumerable接口,从IList开始,集合开始拥有更强大的功能,可以简单理解为IList主要针对动态集合,而ICollection主要针对静态集合.IList里包含了操作集合比较完整的方法,比如添加元素的Add方法,插入到指定元素的Insert方法,清楚所有元素的Clear方法,以及是否存在元素的Contains方法.
Array与IList
虽然Array实现了IList接口,但Array中并不支持IList中的某些方法。比如Contains这样的方法。有人会好奇为什么Array实现了IList接口还不能使用里面的方法呢?因为C#中数组是定长的,而IList是动态的,所以FCL中通过显式实现IList中的某些方法是Array不具有IList中的某些方法。如果想在Array中使用IList的方法,那首先要将Array转换为IList
IList实现了ICollection,而ICollection实现了IEnumerable,为什么数组还要实现上面3个接口呢,实现IList不就好吗
这个问题我在网上查的资料有两点
1.提高代码可读性(这个我想是最重要一条)
2.方便类型转换(其实这个也是提高代码可读性的一部分)
ICloneable
这个接口自成一家,和其他Array实现的接口毫不相干,这个接口是FCL实现设计模式中的原型模式(prototype),在这里其实就是浅复制(shallow copy)功能.
IList<T>,IEnumerable<T>,IEnumerator<T>
这几个接口都是.net 2.0引入的泛型接口,上面所说的接口中除了ICloneable的其他接口都存在于System.Collections命名空间中,而泛型接口存在于System.Collections.Generics命名空间中。泛型我想大家都不陌生了,这里就不讨论了,在这里只想说有了泛型后,前面的接口可以基本不用了:-)
高手请拍砖................