了解 C# 的集合和泛型有助於你處理資料該有的型態
在 C# 中,集合(Collection)是儲存與管理一組資料的容器,最常見的是 List<T> 與 Dictionary<TKey, TValue>;泛型(Generics)則讓你在定義類別或方法時先不指定資料型別,使用時才具體指定,同時兼顧彈性與編譯期的型別安全。本文用實際程式碼說明兩者的概念與使用時機。
甚麼是集合(Collection)?
在 C# 裡,集合是一種非常核心的概念。我們可以利用集合設計簡單到複雜的資料結構。透過集合這樣的物件,我們可以很輕鬆的儲存和管理像是 List<T> 和 Dictionary<TKey, TValue> 這兩種非常常見的集合類型。
Array & List
什麼時候用 Array?什麼時候用 List?在任何語言中,Array 是最基本的資料結構之一,C# 也不例外。當你已經知道所需儲存資料的具體數量時,使用 Array 就會是一個不錯的選擇。我們一般透過 Collection Initializers 來初始化一個 Array:
string[] colorOptions = {"Red", "Blue", "Yellow", "Green"};
至於存取 Array 中的元素,通常要注意存取的資料是否超出 Array 的界限。我們通常使用 foreach 或 for 迴圈來讀取 Array 中的每個元素。foreach 方便但不能修改 Array 中的值,要修改值的話必須透過 for 的語法。
// 可以透過 Array.IndexOf 找出值的 index
var greenIndex = Array.IndexOf(colorOptions, "Green");
// 可以透過 Array.SetValue 修改某 index 的內容
colorOptions.SetValue("Blue", 3);
甚麼是泛型(Generics)?
泛型是 C# 中另一項強大的特性。透過泛型我們可以很彈性地定義物件的類型。也就是說我們不一開始指定具體的資料型別,而是在使用時才具體的指定資料型別。最常見的泛型集合是 List<T>。其中的 T 代表資料型別。List<T> 提供了一個很動態儲存空間的序列,可以存儲任何特定的資料型別。
List<string> cities = new List<string>();
cities.Add("Taipei");
cities.Add("Kaohsiung");
cities.Add("Taichung");
// or
List<int> numbers = new List<int>();
numbers.Add(1);
numbers.Add(2);
numbers.Add(3);
在這個例子中,cities 這個列表專門用於儲存字串類型的資料,如果你在 cities 中加入字串以外的資料型別,編譯器就會報錯,避免了執行期的錯誤。
我們接著看看 Method 運用泛型的範例:
public void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
int a = 10;
int b = 20;
Swap<int>(ref a, ref b);
string x = "Hello";
string y = "World";
Swap<string>(ref x, ref y);
這裡的 Swap<T> 方法可以用於任何資料型別。我們不用像 C 語言一樣重複寫一樣的函式只為了處理不同的資料型別。
如果你的程式是給別人用,但又擔心傳入的資料型別是程式不支援的,你可以運用泛型約束的概念來加以限制:
public interface IMyInterface { }
public class MyClass : IMyInterface { }
public void MyGenericMethod<T>(T myParam) where T : IMyInterface
{
// ...
}
結論
了解 C# 的集合和泛型有助於你處理資料該有的型態。
重點整理
- 已知資料數量時用 Array;需要動態增減時用
List<T>;foreach只能讀取,要修改值必須用for。 - 泛型讓一份程式碼服務多種資料型別(如
Swap<T>),並在編譯期就擋下型別錯誤,避免執行期才爆炸。 - 泛型約束(
where T : IMyInterface)可以限制傳入的型別,讓對外公開的 API 更安全。
常見問題
List<T> 這麼方便,為什麼還要用 Array?
因為 List<T> 的彈性是有成本的:它內部就是一個 Array,容量不夠時會配置更大的新 Array 再把元素整批複製過去。長度固定而且確定不會變的資料(例如設定值、查表用的常數清單)直接用 Array 可以省掉這些重新配置。反過來說,只要數量會變動,List<T> 幾乎都是正確答案,不要為了省一點配置成本自己管理 Array 大小。
泛型有什麼好處?
泛型讓你在定義時不綁定資料型別、使用時才指定,一份程式碼即可服務多種型別;同時編譯器會檢查型別一致性,把錯誤攔在編譯期而非執行期。
什麼是泛型約束?
泛型約束(generic constraints)用 where 關鍵字限制泛型參數必須滿足的條件,例如 where T : IMyInterface 要求 T 必須實作特定介面,避免呼叫端傳入程式不支援的型別。

Leave a Reply