“當你提出疑問并開始思考時,答案就離你不遠了”
@圖片:奧森公園的向日葵 拍攝于2022年7月23日?@攝影師:劉先生
01
—
問題緣起
嚴格來說應該是List<T>,因為.NET的核心基礎類庫中,并沒有List,作為泛型類型的List<T>,對應的非泛型類型是ArrayList。
那么小伙伴們是否清楚,List<T>是哪種數據結構呢?
List被稱作“列表”,相信大家對于"隊列"和"鏈表"都很熟悉,但是"列表"似乎有些陌生,課本教材中將廣義表稱為列表,這個廣義表的定義是:一個多層次的數據結構。直白的說就是表中的元素類型可以不同,這顯然不是.NET中List<T>。
微軟文檔的定義是:
List<T> :表示可通過索引訪問的對象的強類型列表。
這顯然也沒有解答我們問題。
程序世界沒有秘密,一切答案都藏在代碼里。
扒出List<T>的源碼,我們一起看一下吧。【文末附源碼】
02
—
初識List
List<T>的源碼如下:
從源碼及注釋中可知:List<T>是基于數組實現的可擴容的列表。
看一下這幾個私有變量:
T[] _items:是實際的存儲類型,默認構造函數,將_items賦值為一個空數組。
int _size:記錄當前列表中的元素數量。
int _version:這個有意思,我們知道,在遍歷列表過程中,不能對列表進行修改,這個功能便是通過_version實現的,當列表中的元素修改后,_version值會改變,列表遍歷過程中對其進行判斷,進而引發異常,中斷操作。
03
—
List如何擴容
那列表是如何實現數組長度變化的呢?下面3個方法給了我們答案。
從源碼可知,私有變量_size記錄了列表中實際的元素數量,當調用Add(T item)添加元素時,會將_size與_item.Length進行對比,判斷當前數組是否已滿,首次添加元素時,分配的數組默認長度為4,否則重新分配一個2倍長度的數組,然后將原先的元素拷貝到新數組中,實現數組的自動擴容。
04
—
List使用小技巧
1.在已知數據長度的情況下,初始化時,應指定初始長度。
以添加100個元素為例,全部Add(T item)進列表,需要6次數組擴容和數據拷貝,顯然,在已知數據的長度的情況下,應該在創建List對象時,指定初始長度,以減少數組的重寫分配和數據拷貝。
2.另一種擴容方法是:設置Capacity屬性,但需要注意,設置的值不能小于當前列表的元素數量,否則會拋異常。
3.在.NET 6中,新增了一個方法public int EnsureCapacity(int capacity),推薦調用這個方法進行列表擴容,只要參數capacity不小于0,方法就不會報錯。
05
—
總結
結論:List<T>是以數組為底層數據結構,實現的可擴容的列表,并且提供了查找,轉換,排序,遍歷,順序逆轉等便捷的方法。
List<T>中既有Count屬性,又有Count()方法,小伙伴們知道為什么嗎?我們下期再聊。
說明:文中源碼基于.NET 6.0版本,在整理文章內容的過程中,還參考對比了.NET Framework 4.8 、.NET 5.0 幾個不同版本的代碼,不同版本間略有異。
文檔參考:List<T>文檔地址?
源碼鏈接:List<T>源碼地址
喜歡的朋友可以點贊,轉發,加關注