在學習了類別、繼承、多型之後,今天要來學習 C# 中一個非常實用的進階工具:泛型 (Generics)。泛型的主要目的就是:避免重複撰寫相同邏輯的程式碼,增加型別安全 (type safety),避免因為型別轉換造成錯誤,提升效能,因為泛型不需要使用 object 來裝載所有資料。在 C# 的世界中,像是 List<T>
、Dictionary<TKey, TValue>
等集合類別,都是泛型最經典的應用。
先來看一個簡單的泛型例子:
// Declare the generic class.
public class GenericList<T>
{
public void Add(T item) { }
}
public class ExampleClass { }
class TestGenericList
{
static void Main()
{
// Create a list of type int.
GenericList<int> list1 = new();
list1.Add(1);
// Create a list of type string.
GenericList<string> list2 = new();
list2.Add("");
// Create a list of type ExampleClass.
GenericList<ExampleClass> list3 = new();
list3.Add(new ExampleClass());
}
}
在一開頭的:
public class GenericList<T>
{
public void Add(T item) { }
}
是一個泛型類別,<T>
表示類型參數,T 是一個佔位符,可以在類別內部當作類型使用。Add
方法接受一個類型為 T 的參數。
在這個例子中:GenericList創建了一個只能存儲整數的列表。GenericList創建了一個只能存儲字串的列表。GenericList創建了一個只能存儲 ExampleClass實例的列表。
泛型類別與方法結合了可重用性、型別安全性以及效能,這些是非泛型類別與方法所無法同時兼顧的。泛型型別參數會在編譯時期被實際的型別引數取代。在前面的範例中,編譯器會將 T 替換為 int。泛型最常被用於集合 (collections) 以及操作集合的方法。接著看下方的範例程式碼:
// Type parameter T in angle brackets.
public class GenericList<T>
{
// The nested class is also generic, and
// holds a data item of type T.
private class Node(T t)
{
// T as property type.
public T Data { get; set; } = t;
public Node? Next { get; set; }
}
// First item in the linked list
private Node? head;
// T as parameter type.
public void AddHead(T t)
{
Node n = new(t);
n.Next = head;
head = n;
}
// T in method return type.
public IEnumerator<T> GetEnumerator()
{
Node? current = head;
while (current is not null)
{
yield return current.Data;
current = current.Next;
}
}
}
class Program
{
static void Main()
{
// A generic list of int.
GenericList<int> list = new();
// Add ten int values.
for (int x = 0; x < 10; x++)
{
list.AddHead(x);
}
// Write them to the console.
foreach (int i in list)
{
Console.WriteLine(i);
}
Console.WriteLine("Done");
}
}
結果:
T 可用於巢狀的 Node 類別。當 GenericList<T>
使用特定類型(例如 GenericList<int>
)實例化時,每個出現的 T 都會被替換為 int。然後可以看到在Main當中的使用端程式碼如何使用泛型 GenericList<T>
類別建立整數清單。如果更改類型參數,在Main裡面將建立字串或任何其他自訂類型的清單。
System.Collections.Generic
命名空間包含了多個泛型集合類別。建議盡可能使用泛型集合,而不要使用 System.Collections
命名空間中的 ArrayList
這類類別。