.net集合类型(一)

    .net的集合类型都是基于 ICollection 接口、IList 接口、IDictionary 接口,或其泛型集合中的相应接口。IList 接口和 IDictionary 接口都是从 ICollection 接口派生的;因此,所有集合都直接或间接基于 ICollection 接口。在基于 IList 接口的集合中(如 ArrayArrayListList<T>)或直接基于 ICollection 接口的集合中(如 QueueStackLinkedList<T>),每个元素都只包含一个值。在基于 IDictionary 接口的集合中(如 HashtableSortedList 类,或者 Dictionary<TKey, TValue>SortedList<TKey, TValue> 泛型类),每个元素都包含一个键和一个值。KeyedCollection<TKey, TItem> 类较为特别,因为它是值中带有嵌入键的值列表,因此它的行为既像列表又像字典。

      一.基于IList的接口的集合:ArrayArrayListList<T>

      有一个园友的文章已经对此做出总结了,主要有这么几点:

      1..NET所有数组如(int[],string[]等等)都是继承自Array类。Array继承自ICloneable, IList, ICollection,IEnumerable这几个接口,并且提供了一些对数组进行基本操作的静态方法。

      2.ArrayList是Array的一层封装,实际数据操作还是针对Array.通过源码可以发现ArrayList有个私有成员object[]item.ArrayList其他方法(如IndexOf)很多都是调用了Array的静态方法。但是有一个方法除外,就是Add,调用Add时会判断数组是否已满,如果满的话就调用EnsureCapacity方法创建一个更长的数组,将原来的旧数据都复制过去。这也就是ArrayList和Array的根本区别,ArrayList可以实现动态增长。

      3.ArrayList里面的数组的object类型的,因此当使用ArrayList来存储值类型的时候就会造成很多装箱与拆箱的操作。在.NET2.0引入了泛型,而ArrayList对应的泛型集合就是List<T>.使用List<T>的好处就显而易见了,避免装箱拆箱,可以实现项动态增长。在《Effective C#》中有这样一条规则,就是说:在初始化List之前最好对List初始化大小。通过源码来探究下原因。

List<int> list = new List<int>();

    上面这句代码调用了List<T>的无参数构造函数,List还有一个静态构造函数(静态构造函数会在创建第一个实例或者引用任何静态成员之前被调用,仅被调用一次),初始化_emptyArray静态成员,之所以这样做原因是创建一个静态的_emptyArray,在下次 new List<int>()得以重复使用。接下来调用无参数构造函数。 

 

View Code
1 public List()
2 {
3 this._items = List<T>._emptyArray;//this.items的类型是T[]items;
4 }

      当我们调用Add方法时:   EnsureCapacity方法: 调用EnsureCaptity方法,先将T[]items

View Code
1 public void Add(T item)
2 {
3 if (this._size == this._items.Length)
4 {
5 this.EnsureCapacity(this._size + 1);
6 }
7 this._items[this._size++] = item;
8 this._version++;
9 }
View Code
1 private void EnsureCapacity(int min)
2 {
3 if (this._items.Length < min)
4 {
5 int num = (this._items.Length == 0) ? 4 : (this._items.Length * 2);
6 if (num < min)
7 {
8 num = min;
9 }
10 this.Capacity = num;//在这里重新设置数组大小
11 }
12 }

      当我们使用new List<int>()时,并没有给this._size和this._items.Length赋值,它们的值都为0,因此第一次调用Add的时候会长度设置为4项,当超过4时就设置为8.如果现在数据项大概有1000项,再没有指定初始值的情况下EnsureCapcity将会被调用9次。会重复的新分配内存给T[]items然后复制元素,GC回收内存。如果指定一个大概的初始值将不会使EnsureCapcity被重复调用,但是话说回来,这个大概不好大概的时候呢?

       二.基于IDictionary的Hashtable和Dictionary类。

       Hashtable 类和 Dictionary<TKey, TValue> 泛型类实现 IDictionary 接口。Dictionary<TKey, TValue> 泛型类还实现 IDictionary<TKey, TValue> 泛型接口。因此,这些集合中的每个元素都是一个键/值对。

Hashtable 对象由包含集合元素的存储桶组成。存储桶是 Hashtable 中各元素的虚拟子组,与大多数集合中进行的搜索和检索相比,存储桶可令搜索和检索更为便捷。每一存储桶都与一个哈希代码关联,该哈希代码是使用哈希函数生成的并基于该元素的键,插入和查询的复杂度是O(1)。

哈希函数是基于键返回数值哈希代码的算法。键是正被存储的对象的某一属性的值。哈希函数必须始终为相同的键返回相同的哈希代码。一个哈希函数能够为两个不同的键生成相同的哈希代码,但从哈希表检索元素时,为每一唯一键生成唯一哈希代码的哈希函数将令性能更佳。

Hashtable 中用作元素的每一对象必须能够使用 GetHashCode 方法的实现为其自身生成哈希代码。但是,还可以通过使用接受 IHashCodeProvider 实现作为参数之一的 Hashtable 构造函数,为 Hashtable 中的所有元素指定一个哈希函数。

在将一个对象添加到 Hashtable 时,它被存储在存储桶中Hastable类里面有个数据类型叫bucket,是一个结构体,其中一个object key存放这key经过hash之后的值,value存放着,key相应的值。在 Hashtable 内搜索一个值时,将为该值生成哈希代码,并且搜索与该哈希代码关联的存储桶的value。

         Dictionary<TKey, TValue>就是Hastable的泛型实现。

       三.SortedList 和 SortedDictionary 集合类型

      System.Collections.SortedList 类、System.Collections.Generic.SortedList<TKey, TValue> 泛型类和 System.Collections.Generic.SortedDictionary<TKey, TValue> 泛型类类似于 Hashtable 类和 Dictionary<TKey, TValue> 泛型类,因为它们也实现 IDictionary 接口,但是它们以基于键的排序顺序维护元素,没有哈希表的 O(1) 插入和检索特性。这三个类具有若干共性:

posted @ 2011-05-09 17:52  雁北飞  阅读(466)  评论(0编辑  收藏  举报