1. 程式人生 > >C# ArrayList原始碼剖析

C# ArrayList原始碼剖析

原始碼版本為 .NET Framework 4.6.1

本系列持續更新,敬請關注

有投入,有產出。

陣列是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)。

  1. 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()。

  1. 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)

  1. Sort():將整個 ArrayList 中的元素進行排序。在ArrayList的排序方法全部在內部呼叫了Sort(Int32, Int32, IComparer),進行排序。
  2. Sort(IComparer):使用指定的比較器對整個 ArrayList 中的元素進行排序。
  3. 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了,以使在某些情況下,可以避免內部陣列的重複建立和資料位置的變換。

相關推薦

C# ArrayList原始碼剖析

原始碼版本為 .NET Framework 4.6.1 本系列持續更新,敬請關注 有投入,有產出。 陣列是C#中最基礎的一種資料型別,一旦初始化之後,容量便已經確定。若想要動態擴充容量,那麼集合可以滿足這點需求。ArrayList是C#最常用也是最基礎

ArrayList原始碼剖析~

包路徑:package java.util; 一、基本屬性 1、private  static  final  long  serialVersionUID  =  8683452581122892189L;   

C++ STL原始碼剖析——stl_alloc.h

stl_alloc.h # // Comment By: 凝霜 # // E-mail: [email protected] # // Blog: http://blog.csdn.net/mdl13412 # # //

C# Hashtable原始碼剖析

原始碼版本為 .NET Framework 4.6.1 本系列持續更新,敬請關注 有投入,有產出。 Hashtable實現一個雜湊表(也叫散列表),將鍵對映到相應的值。任何非 null 物件都可以用作鍵。 雜湊表的實現比較複雜,最好先了解一下相關的方

【實踐】Zookeeper c client原始碼剖析——不同event觸發的條件和時機

watcher,watcherCtx));//關鍵語句:add_stat_completion函式往zh->sent_requests(即傳送請求佇列)中新增非同步完成資料結構物件(包括非同步回撥型別COMPLETION_STAT和回撥函式地址,同時該物件中還儲存著當關注的事件發生時要回調的watch

【Java集合原始碼剖析ArrayList原始碼剖析

本篇博文參加了CSDN博文大賽,如果您覺得這篇博文不錯,希望您能幫我投一票,謝謝!ArrayList簡介    ArrayList是基於陣列實現的,是一個動態陣列,其容量能自動增長,類似於C語言中的動態申請記憶體,動態增長記憶體。    ArrayList不是執行緒安全的,只

ArrayList原始碼剖析與程式碼實測

# ArrayList原始碼剖析與程式碼實測(基於OpenJdk14) [toc] * 寫本篇部落格的目的在於讓自己能夠更加了解Java的容器與實現,能夠掌握原始碼的一些實現與思想,選擇從ArrayList入手是因為ArrayList相對來說是實現較為簡單的容器,底層實現依賴與陣列,將ArrayList整

原始碼剖析】tinyhttpd —— C 語言實現最簡單的 HTTP 伺服器

    tinyhttpd 是一個不到 500 行的超輕量型 Http Server,用來學習非常不錯,可以幫助我們真正理解伺服器程式的本質。     看完所有原始碼,真的感覺有很大收穫,無論是 unix 的程式設計,還是 GET/POST 的 Web 處理流程

【Linux 1.0核心原始碼剖析】執行程式——exec.c

父程序 fork的子程序的目的自然不是建立一個幾乎與自己一模一樣的程序。而是通過子程序呼叫 exec 函式簇去執行另外一個程式。exec() 系統呼叫必須定位該執行檔案的二進位制映像,載入並執行它。 exec() 的Linux實現支援不同的二進位制格式,這是通過 linux

【特徵匹配】SIFT原理與C原始碼剖析

     SIFT的原理已經有很多大牛的部落格上做了解析,本文重點將以Rob Hess等人用C實現的程式碼做解析,結合程式碼SIFT原理會更容易理解。一些難理解點的用了☆標註。       歡迎大家批評指正! 轉載請註明出處:http://blog.csdn.net/l

【Linux 核心網路協議棧原始碼剖析】socket.c——BSD Socket層(1)

寫在前面:本系列文章先把各個層對應的檔案原始碼剖析一遍,最後再穿插起來,理清整個協議棧網路資料包的上下傳送通道,從整體實現上進行把握。         圖片來源於《Linux 核心網路棧原始碼情景分析》 更上層函式:tcp socket函式介紹。本篇則是介紹BSD Sock

【學習筆記】C# ArrayList

tde 獲取 style demo key ren mov cnblogs content 集合 集合是種容器,在程序中,使用集體管理相關對象組 集合分為非泛型集合和泛型集合 非泛型集合 使用非泛型集合需要引入命名空間System.Collections Arra

(3.2)狄泰軟件學院C++課程學習剖析

cti 學院 函數定義 關鍵字 但是 function 判斷 ima c語言 對課程前面40課的詳細回顧分析 1、 2、 3、c++中可以使用const常量代替宏常數定義;同樣我們可以使用內聯函數來替代宏代碼片段。內聯函數在聲明時inline關鍵字必須和函數定義

C# ArrayList的用法

知新樹 寧金峰ArrayList類是一個特殊的數組。通過添加和刪除元素,就可以動態改變數組的長度。一、優點1. 支持自動改變大小的功能2. 可以靈活的插入元素3. 可以靈活的刪除元素4. 可以靈活訪問元素二、局限性跟一般的數組比起來,速度上差些用微軟的話講:“添加到 ArrayList 中的任何引用或值類型都

C語言深度剖析 -- 第一課 基本數據類型

中一 eof bsp div pri style pre short 一段 第一課 -- 基本數據類型分析 任何編程語言,它都要操作存在內存中的數據, 變量的本質是內存中一段數據空間的別名 1 #include <stdlib.h>

C語言深度剖析》筆記

可變 單詞 符號 所有 只讀 存儲 nbsp min stat 關鍵字: C語言關鍵字32個: 關鍵字 意 義 auto 聲明自動變量,

菜鳥帶你看原始碼——看不懂你打我ArrayList原始碼分析(基於java 8)

文章目錄 看原始碼並不難 軟體環境 成員變數: 構造方法 核心方法 get方法 remove方法 add方法 結束 看原始碼並不難 如何學好程式設計?如何寫出優質的程式碼?如

python重試庫retryiny原始碼剖析

  上篇博文介紹了常見需要進行請求重試的場景,本篇博文試著剖析有名的python第三方庫retrying原始碼。    在剖析其原始碼之前,有必要講一下retrying的用法,方便理解。    安裝:   pip install retryin

Caffe框架原始碼剖析(6)—池化層PoolingLayer

    卷積層ConvolutionLayer正向傳導的目標層往往是池化層PoolingLayer。池化層通過降取樣來降低卷積層輸出的特徵向量,同時改善結果,不易出現過擬合。最常用的降取樣方法有均值取樣(取區域平均值作為降取樣值)、最大值取樣(取區域最大值作為降取樣值)和隨機

Caffe框架原始碼剖析(5)—卷積層ConvolutionLayer

ConvolutionLayer是BaseConvolutionLayer的子類,功能較為簡單。類中不包含成員變數,僅包含幾個虛擬函式的實現。 conv_layer.hpp標頭檔案的定義如下: template <typename Dtype> class Convoluti