剖析.NET Framework源码—数据结构List<T> (二)

接着,我们看看List中对数据进行操作的方法:

(2)Add:将对象添加到 List<T>的结尾处。

        public void Add(T item)

        {

            if (_size == _items.Length) EnsureCapacity(_size + 1);

            _items[_size++] = item;      

            _version++;

        }

这个方法有两个要点:

1. 当前List已满(_size==_items.Length)时,首先需要进行扩容!

2. 往List内部数组_items中添加新元素的操作_items[_size++] = item存在        多线程并发访问的问题!

(3)AddRange:将指定集合的元素添加到 List的末尾

        public void AddRange(IEnumerable<T> collection)

        {

            InsertRange(_size, collection);

        }

这个方法对collection不做任何处理,直接调用InsertRange方法。

(4)InsertRange : 将集合中的所有元素插入List的指定索引处。

// Inserts the elements of the given collection at a given index. If

        // required, the capacity of the list is increased to twice the previous

        // capacity or the new size, whichever is larger.  Ranges may be added 

        // to the end of the list by setting index to the List's size. 

        public void InsertRange(int index, IEnumerable<T> collection)

        {

            if (collection == null)

            {

                throw new ArgumentNullException();

            }

 

            if ((uint)index > (uint)_size)

            {

                throw new ArgumentOutOfRangeException();

            }

 

            ICollection<T> c = collection as ICollection<T>;

            if (c != null)

            {    

                int count = c.Count;

                if (count > 0)

                {

                    EnsureCapacity(_size + count);

 

                    if (index < _size)

                    {

                        Array.Copy(_items, index, _items, index + count, _size - index);

                    }

 

                    if (this == c)

                    {

                        Array.Copy(_items, 0, _items, index, index);

                        Array.Copy(_items, index + count, _items, index * 2, _size - index);

                    }

 

                    else

                    {

                        T[] itemsToInsert = new T[count];

                        c.CopyTo(itemsToInsert, 0);

                        itemsToInsert.CopyTo(_items, index);

                    }

                    _size += count;

                }

            }

            else

            {

                using (IEnumerator<T> en = collection.GetEnumerator())

                {

                    while (en.MoveNext())

                    {

                        Insert(index++, en.Current);

                    }

                }

            }

            _version++;

        }

这个方法很长,不过其思路是很清晰的。首先进行两次参数合法性验证,如果某次验证失败了,就直接抛个异常出去。注意第二个合法性检查,它检查的是要插入collection元素到List的指定索引位置index,其合法区间是[0 , _size]!

接着,会把传入的collection尝试转 换为ICollection<T>接口,如果转换成功,说明collection实现了ICollection接口,那么就执行if语句块;否则,执行else语句块。

If语句块的基本思路是:首先获得collection中元素的个数count,接着调用EnsureCapacity(_size + count)以确定是否需要扩容,然后根据所要插入的索引位置index在内部数组_items中腾出count个位置以便存储collection中的元素。紧接着创建一个itemsToInsert辅助数组用于存放collection中的所有元素,然后把itemsToInsert中所有的元素(count个)拷贝到List的内部数组_items中早已腾出的空间中(count个位置)。最后再把_size的值加上count。注意,在if语句块中我们还有一个地方未涉及到,就是if (this == c)大括号中的代码,这是一种特殊情况,表示要插入的collection就是当前这个List,分析思路类似!

else语句块的思路是:利用collection的迭代器,将collection中的元素一个一个插入到_items数组的指定索引index位置后面!注意这里会调用到Insert方法,这也是List的核心方法之一。

(5)Insert(int index, T item):将元素插入List的指定索引处

        public void Insert(int index, T item)

        {

            // index的合法区间是[0 , _size]

            if ((uint)index > (uint)_size)

            {

                throw new ArgumentOutOfRangeException();

            }

 

            if (_size == _items.Length) EnsureCapacity(_size + 1);

 

            if (index < _size)

            {

// index处及后面所有元素后移一位,腾出index这个位置!

                Array.Copy(_items, index, _items, index + 1, _size - index);

            }

 

 //要插入的元素就放在指定的index位置处!

            _items[index] = item;

            _size++;

            _version++;

        }

(6)CopyTo :三个重载,将 List或它的一部分复制到一个数组中

    //参数array : 目标数组

    //参数arrayIndex : 目标数组开始放置处的索引

 public void CopyTo(T[] array, int arrayIndex)

        {

            Array.Copy(_items, 0, array, arrayIndex, _size);

        }

    //参数index : 源List中复制开始位置的从零开始的索引

    //参数count : 要复制的元素个数

public void CopyTo(int index, T[] array, int arrayIndex, int count)

        {

            if (_size - index < count)

            {

                throw new ArgumentException();

            }

            Array.Copy(_items, index, array, arrayIndex, count);

        }

        //将整个List复制到类型兼容的一维数组中,从目标数组的0索引开始放置

 public void CopyTo(T[] array)

        {

            CopyTo(array, 0);

        }

(7)Contains(T item) : 确定某元素是否在List中

    public bool Contains(T item)

        {

            if ((Object)item == null)

            {

                for (int i = 0; i < _size; i++)

                {

                    if ((Object)_items[i] == null)

                        return true;

                }

                return false;

            }

            else

            {

                EqualityComparer<T> c = EqualityComparer<T>.Default;

 

                for (int i = 0; i < _size; i++)

                {

                    if (c.Equals(_items[i], item)) return true;

                }

                return false;

            }

        }

     该方法有两条执行路径。当所要查找的元素为null时执行if语句块;否则执行else语句块。

 两条执行路径的基本思路都是一样的:遍历List内部数组,如果找到了所要查找的元素,则返回True!注意else语句块,首先获得了一个泛型T的相等性比较器EqualityComparer<T>,然后通过相等性比较器的Equals方法比较两个对象是否相等!

posted on 2010-02-03 01:43  张念  阅读(1153)  评论(0编辑  收藏  举报

导航