.net集合类的研究--Array,ArrayList,List<T>

最近研究Nhibernate,看着样例代码一知半解,苦恼万分,发现中间又引用了一个Iesi.Collections,不禁要产生疑问--为什么要专门引用一个集合类程序集?这个程序集里的集合数组类与.net自带的有什么不一样?结果此问题一出就一发不可收拾,扪心自问冒出了一大堆的问题--.net有哪些集合类?array和ArrayList有什么区别?Hashtable与集合有什么不一样?....等等.这时才意识到,如果对.net本身提供的集合类不了解,根本不会明白引用Iesi.Collections的用意.

由<<CLR via C#>>的书中所说:"所有的数组(如int[],FileStream[],object[])都隐式派生自System.Array,所有数组都隐式实现IEnumerable,ICollection,IList",所以先从Array开始研究,用Reflector工具找到Array源代码,发现除去一堆的静态方法如Sort,Find,BinarySearch以外,几乎就不剩什么东西了.

其中比较重要的一点是Array仅仅用显示接口实现了一个私有IList.Add方法,这意味着:Array实例没有办法调用Add方法,一旦初始化以后,长度不可变.

int IList.Add(object value)
{
throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
}

同样通过源代码可以看到ArrayList和Array的区别,ArrayList内置了一个Array变量 _items(代码中红色标出),

也就是说:ArrayList是Array的一层封装,实际数据操作还是针对Array.

[Serializable, ComVisible(true), DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(ArrayListDebugView))]
public class ArrayList : IList, ICollection, IEnumerable, ICloneable
{
// Fields
private const int _defaultCapacity = 4;
private object[] _items;
private int _size;
// Methods
  ...........
}

ArrayList有Add方法,当Add方法发现内部的object[]容量已满时,便会调用一个方法自动扩充object[]容量,既然ArrayList的实质是操作object[],而Array长度不可变,那么如何扩充?其实说白了,就是通过调用EnsureCapacity方法再创建一个更长的object[]数组,然后把原数组复制到新的数组中.

ArrayList的很多方法如Sort,Indexof,内部都是调用了Array的静态方法,如IndexOf方法:

public virtual int IndexOf(object value)
{
return Array.IndexOf(this._items, value, 0, this._size);
}

.net2.0以后出现了泛型,目的是为了避免装箱拆箱操作造成的性能损失.ArrayList对应的泛型集合就是List<T>.

由于泛型的出现,List<T>内部操作的不再是object[],而是T[],提供的很多方法如Sort,IndexOf等,同ArrayList类一样,内部也是调用Array的静态方法来操作数组.

因为Array的局限性,List<T>的一些方法会用到循环,如Find方法:

public T Find(Predicate<T> match)
{
if (match == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
for (int i = 0; i < this._size; i++)
{
if (match(this._items[i]))
{
return this._items[i];
}
}
return default(T);
}

其中Predicate<T>是一个委托,在.net内部定义,需要一个类型为T的参数,返回值为bool.

知道这些可以避免我们把这些方法用在自己写的循环中,造成性能损失.


Array,ArrayList和List<T>在使用上如何选择呢?由于泛型可以避免装箱拆卸的性能损失,2.0以后的泛型集合基本上能淘汰以前的非泛型集合,所以ArrayList不做考虑,只比较Array和List<T>.

标准答案:确定了Array大小的时候,选用Array,不确定大小时,使用List<T>.

个人观点:如果数组是1维的,使用List<T>和Array之间的性能损失微乎其微,而List<T>可以带来更大的灵活性,因为很多时候想法和业务逻辑是多变的,建议多用List<T>.

刚写完后,查了博客园,发现这个问题在园子里已经被说的很透彻了,给出链接重新理解List<T>.

posted @ 2011-05-02 22:17  许两会  阅读(1372)  评论(2编辑  收藏  举报