C# ArrayList源码剖析
2016-04-19 15:29
603 查看
源代码版本为 .NET Framework 4.6.1
数组是C#中最基础的一种数据类型,一旦初始化之后,容量便已经确定。若想要动态扩充容量,那么集合可以满足这点需求。ArrayList是C#最常用也是最基础的一个动态数组。
ArrayList在System.Collections中,实现了IList接口(IList:表示可按照索引进行访问的非泛型集合对象)。
如此来,ArrayList可以干点什么事情呢?
1. 可以动态扩容;
2. 插入/删除 比较便捷;
为了防止废话过多而导致翻船,上代码:
ArrayList中的数据是由一个内部数组来进行维护的,一个私有的Object数据(Object 你就是万能的造物主啊~)
2.RemoveAt(Int32):移除 ArrayList 的指定索引处的元素。
3.RemoveRange(Int32, Int32):从 ArrayList 中移除一定范围的元素。
Sort(IComparer):使用指定的比较器对整个 ArrayList 中的元素进行排序。
Sort(Int32, Int32, IComparer):使用指定的比较器对 ArrayList 中某个范围内的元素进行排序。
4.Reverse():将整个 ArrayList 中元素的顺序反转。
5.Reverse(Int32, Int32):将指定范围中元素的顺序反转。
ArrayList可以说是C#中最简单的一种数据结构了,再使用ArrayList时为了获得一些性能上的提升,尽量在可预知的容量大小范围内使用一个固定的初始容量来构建ArrayList了,以使在某些情况下,可以避免内部数组的重复创建和数据位置的变换。
本系列持续更新,敬请关注
有投入,有产出。数组是C#中最基础的一种数据类型,一旦初始化之后,容量便已经确定。若想要动态扩充容量,那么集合可以满足这点需求。ArrayList是C#最常用也是最基础的一个动态数组。
ArrayList在System.Collections中,实现了IList接口(IList:表示可按照索引进行访问的非泛型集合对象)。
如此来,ArrayList可以干点什么事情呢?
1. 可以动态扩容;
2. 插入/删除 比较便捷;
为了防止废话过多而导致翻船,上代码:
ArrayList中的数据是由一个内部数组来进行维护的,一个私有的Object数据(Object 你就是万能的造物主啊~)
private Object[] _item[]; private int _size;//ArrayList的容量 private const int _defaultCapacity = 4;//默认的容量 private static readonly Object[] emptyArray = EmptyArray<Object>.Value; //默认的空数组
- 添加元素:Add(Object) ,AddRange(ICollection),Insert(Int32, Object),InsertRange(Int32, ICollection)。
Add(Object):将对象添加到 ArrayList 的结尾处。public virtual int Add(Object value) { Contract.Ensures(Contract.Result<int>() >= 0);//后置契约,返回值必须大于等于0 //动态扩容的核心方法,当ArrayList的容量等于内部存放数据的数组长度时,进行扩容 if (_size == _items.Length) EnsureCapacity(_size + 1); _items[_size] = value;//在ArrayList末尾索引处写入值 _version++; return _size++;//返回数组ArrayList的容量 }
//动态扩容的核心方法,一次扩容长度为初始容量的2倍,容量不得超出long的最大范围 private void EnsureCapacity(int min) { if (_items.Length < min) { int newCapacity = _items.Length == 0 ? _defaultCapacity: _items.Length * 2; //Array.MaxArrayLength为long的最大值 if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength; if (newCapacity < min) newCapacity = min; Capacity = newCapacity; } }
//自动扩容的实现原理是 创建一个更大容量新的组数,将原数组的数据搬至新组数 public virtual int Capacity { get { Contract.Ensures(Contract.Result<int>() >= Count); return _items.Length; } set { if (value < _size) { throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity")); } Contract.Ensures(Capacity >= 0); Contract.EndContractBlock(); if (value != _items.Length) { if (value > 0) { Object[] newItems = new Object[value]; if (_size > 0) { Array.Copy(_items, 0, newItems, 0, _size); } _items = newItems; } else { _items = new Object[_defaultCapacity]; } } } }
2. AddRange(ICollection):添加 ICollection 的元素到 ArrayList 的末尾。该方法在内部调用了InsertRange(Int32, ICollection)方法
public virtual void AddRange(ICollection c) { InsertRange(_size, c); }
3. Insert(Int32, Object) :将元素插入 ArrayList 的指定索引处。
public virtual void Insert(int index, Object value) { if(index < 0 || index > _size) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_ArrayListInsert")); Contract.EndContractBlock(); //扩容检查 if(_size == _items.Length) EnsureCapacity(_size + 1); //插入到指定索引处,可以看出,由于需要移动元素的位置,相对于Add直接插入到末尾来说,效率慢了点 if(index < _size){ Array.Copy(_items, index, _items, index + 1, _size - index); } _items[index] = value; _size++; _version++; }
4. InsertRange(Int32, ICollection):将ICollection中的元素插入到 ArrayList 中指定索引处。
public virtual void InsertRange(int index, ICollection c) { if (c==null) throw new ArgumentNullException("c", Environment.GetResourceString("ArgumentNull_Collection")); if (index < 0 || index > _size) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index")); Contract.EndContractBlock();//契约结尾 int count = c.Count;//即将要添加到ArrayList的元素数量 if (count > 0) { //每次添加元素,都会进行扩容判断 EnsureCapacity(_size + count); //友谊的小船说翻就翻,看看微软大神在功能与性能上所做的取舍吧 if (index < _size) { //移动元素位置 Array.Copy(_items, index, _items, index + count, _size - index); } //后面这段没有用for循环,也许是微软大神为了代码的重用吧? //创建新数组用于存储即将插入ArrayList的元素 Object[] itemsToInsert = new Object[count]; c.CopyTo(itemsToInsert, 0); //将元素插入对应的索引处 itemsToInsert.CopyTo(_items, index); _size += count; _version++; } }
- 移除元素:Remove(Object),RemoveAt(Int32),RemoveRange(Int32, Int32),Clear()。
Remove(Object):从 ArrayList 中移除特定对象的第一个匹配项。在内部调用了IndexOf(Int32)和RemoveAt(Int32)。public virtual void Remove(Object obj) { Contract.Ensures(Count >= 0); //调用IndexOf(Int32)获取元素的索引 int index = IndexOf(obj); if(index >= 0) RemoveAt(index); }
2.RemoveAt(Int32):移除 ArrayList 的指定索引处的元素。
public virtual void RemoveAt(int index) { if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index")); Contract.Ensures(Count >= 0); Contract.EndContractBlock(); _size--;//移除元素,容量自减1 //移除元素也会导致元素位置的变动,导致效率降低 if (index < _size) { Array.Copy(_items, index + 1, _items, index, _size - index); } _items[_size] = null; _version++; }
3.RemoveRange(Int32, Int32):从 ArrayList 中移除一定范围的元素。
public virtual void Clear() { if (_size > 0) { //快刀斩乱麻 Array.Clear(_items, 0, _size); _size = 0; } _version++; }
- 排序:Sort(),Sort(IComparer),Sort(Int32, Int32, IComparer),Reverse(),Reverse(Int32, Int32)
Sort():将整个 ArrayList 中的元素进行排序。在ArrayList的排序方法全部在内部调用了Sort(Int32, Int32, IComparer),进行排序。Sort(IComparer):使用指定的比较器对整个 ArrayList 中的元素进行排序。
Sort(Int32, Int32, IComparer):使用指定的比较器对 ArrayList 中某个范围内的元素进行排序。
public virtual void Sort(int index, int count, IComparer comparer) { if (index < 0) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (count < 0) throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (_size - index < count) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); Contract.EndContractBlock(); //使用了基础数组排序 Array.Sort(_items, index, count, comparer); _version++; }
4.Reverse():将整个 ArrayList 中元素的顺序反转。
public virtual void Reverse(int index, int count) { if (index < 0) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (count < 0) throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (_size - index < count) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); Contract.EndContractBlock(); Array.Reverse(_items, index, count); _version++; }
5.Reverse(Int32, Int32):将指定范围中元素的顺序反转。
public virtual void Reverse(int index, int count) { if (index < 0) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (count < 0) throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (_size - index < count) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); Contract.EndContractBlock(); Array.Reverse(_items, index, count); _version++; }
ArrayList可以说是C#中最简单的一种数据结构了,再使用ArrayList时为了获得一些性能上的提升,尽量在可预知的容量大小范围内使用一个固定的初始容量来构建ArrayList了,以使在某些情况下,可以避免内部数组的重复创建和数据位置的变换。
相关文章推荐
- 如何在 Linux/Windows/MacOS 上使用 .NET 进行开发
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- 如何在 Linux 中安装微软的 .NET Core SDK
- ruby 数组使用教程
- Ruby中的数组和散列表的使用详解
- C#数据结构之顺序表(SeqList)实例详解
- C#.NET获取拨号连接的宽带连接方法
- C#实现AddRange为数组添加多个元素的方法
- C#比较二个数组并找出相同或不同元素的方法
- C#.Net ArrayList的使用方法
- C#动态调整数组大小的方法
- 详解Lua中的数组概念知识
- Lua教程(七):数据结构详解
- Perl中的列表和数组学习笔记
- 探索PowerShell (八) 数组、哈希表(附:复制粘贴技巧)
- C#中数组初始化与数组元素复制的方法
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#交错数组用法实例
- Linux Shell 数组建立及使用技巧
- PowerShell数组的一些操作技巧