前言

C# 的 List 與 Array 有很多類似之處

在看 LINQ 介紹的時候,出現了兩個 LINQ 函式:ToList()ToArray()

看到這兩個詞之後我不禁好奇,List 與 Array 又有何不同呢?

C# 的 Collections 資料型別

C# 中的 Collections 資料型別有很多種,包含:

  • ArrayList
  • List
  • SortedList
  • Dictionary
  • Hashtable
  • Stack
  • Queue

而想討論的是 Array、List 與 ArrayList 這三種

Array

Array 定義

Array 的定義如下:

An array is the data structure that stores a fixed number of literal values (elements) of the same data type. Array elements are stored contiguously in the memory.

由定義我們知道,C# 使用連續的記憶體空間存放 Array,因此在初始化的當下,就決定了這個 Array 的長度

我們可以替換 Array 裡面成員的值,但無法新增或是刪除裡面的成員

因此,若要增加陣列的長度,就要再建立一個更大長度的新陣列,然後將就原陣列的所有成員 copy 過去,再將原陣列刪除

宣告一個 Array,可以這樣寫:

int[] numbers;
string[] colors;

或在宣告的時候直接初始化:

int[] numbers = new int[3] { 1, 2, 3 };
string[] colors = new string[3] { "red", "green", "blue" };

若用 var 初始化陣列,則可以省去陣列長度,讓編譯器從成員去自行推斷陣列的長度:

var numbers = new int[] { 1, 2, 3 };
var colors = new string[] { "red", "green", "blue" };

更簡短的寫法:

int[] numbers = { 1, 2, 3 };
string[] colors = { "red", "green", "blue" };

在初始化的時候,必須指定 Array 的長度

此外,成員的數量也要與長度相同,不然就會報錯

ArrayList

ArrayList 的定義

ArrayList 的定義如下:

In C#, the ArrayList is a non-generic collection of objects whose size increases dynamically. It is the same as Array except that its size increases dynamically.

因為 ArrayList 在宣告的時候,並不用定義其內部成員的型別,意即每個成員可以是不一樣的型別

List 跟 ArrayList 都不使用連續的記憶體來儲存資料,因此它的長度是動態的,會隨著成員的數量而增減

宣告一個 ArrayList 有兩種方法:

ArrayList list = new ArrayList();

var list = new ArrayList();

可以用 Add() 方法,隨時加入新的成員至 ArrayList:

var list = new ArrayList();
list.Add(1);
list.Add("hello");
list.Add(false);
list.Add(null);

或用物件初始子(object initializer syntax)的寫法:

var list = new ArrayList()
{
  1, "hello", false, null
};

由此可見,ArrayList 中的成員不一定是同型別的,這跟 JavaScript 的陣列很相似

ArrayList 的方法

ArrayList 提供一些方法,來操作內部的成員,剛才範例中的 Add() 就是其中之一

除此之外,還有 AddRange()Insert()Remove()Sort()IndexOf⋯⋯ 等

ArrayList 的屬性

比較常見的屬性有:CapacityCount

Count 很好理解,也就是 ArrayList 的成員數,相當於 JavaScript 的 Array.prototype.length

Capacity 則代表這個 ArrayList 可以裝載多少成員,這其實跟記憶體的配置容量有關

List

List 的定義

List 的定義如下:

The List<T> is a collection of strongly typed objects that can be accessed by index and having methods for sorting, searching, and modifying list. It is the generic version of the ArrayList that comes under System.Collections.Generic namespace.

List 其實是泛型版本的 ArrayList,在 List 裡面的每個成員,其型別都要符合傳入的 T 泛用型別

List 來自於 System.Collections.Generic namespace,而 ArrayList 來自於 System.Collections

宣告、初始化、對成員的操作方法,基本上都跟 ArrayList 一樣

List 的屬性

List 同 ArrayList 有 Count 這個屬性,表成員的數量

List 的方法

List 有些方法與 ArrayList 一樣,詳細的範例可以參考 TutorialsTeacher 網站

關於記憶體的使用

List 與 Array 將資料儲存至記憶體的方式不太一樣,在這篇文章分析了兩者的相異之處

以 List 而言,在建立一個 List 的時候,會先定義長度為 4 的陣列

當裡面的 item 數量大於 4 時,則再創建一個新的陣列,其長度為原本的兩倍(也就是 8),並將舊的陣列從記憶體中釋放(dereference, garbage collection 機制)

再下一次遇到 item 數量超越陣列長度的時候,就再做一次(長度增為 16)

可以從下面的範例印證:

可以看到,Capacity 確實是依照兩倍的方式增長

最後面,用 TrimExcess() 這個方法將 Capacity 多餘未使用的記憶體移除,達成 Count 跟 Capacity 相等。然後呼叫 Clear() 清空所有成員,Count 歸零,Capacity 則維持原狀

比較表

ArrayArrayListList
記憶體使用靜態且連續的記憶體使用動態且不連續的記憶體使用動態且不連續的記憶體
成員同型別資料異型別資料同型別資料
命名空間System.ArraySystem.CollectionsSystem.Collections.Generic
成員修改只能夠變動成員,無法增減可增減成員可增減成員

後記

研究過 Array 及 List 之後,才知道最重要的差異就在於記憶體使用

然而,我在專案裡幾乎只有看到 List<T>,因為我們處理的資料大部分都是集合物件,也大量使用 LINQ 函式來處理資料

因此相較於 Array,List 的靈活度也就顯而易見了

參考資料