1. 數組到泛型集合#
string[] names = new string[4]; // 需指定大小
ArrayList names = new ArrayList();
names.AddRange(new object[]
{
"Rose",
"Jack",
new int?(5) // 可合法進行編譯, 因為符合 object
});
foreach (string name in names) Console.WriteLine(name);
// 缺少型別檢查, 在執行隱性類型轉換(int? 轉 string)時會出錯
- 專用對象集合缺少撰寫程式碼的靈活性(如無法以靜態方式寫通用方法)、且維護成本較高
StringCollection names = new StringCollection();
names.AddRange(new string[]
{
"Rose",
"Jack",
"Gozilla"
});
static void printNames(StringCollection names)
{
foreach (string name in names) Console.WriteLine(name);
}
- 泛型可以解決以上問題
- 在初始化時不須先設定大小
- 在添加錯誤型別的元素,在編譯時期就會報錯
- 兼容各種類型,省去撰寫與維護的成本
List<string> names = new List<string>{
"Rose",
"Jack",
"Gozilla"
};
static void printList(List<T> list) {
foreach (T item in list) Console.WriteLine(item);
}
2. 靜態方法取代建構式#
- 由於在泛型函式調用時,會進行類型推斷,故可以透過靜態方法簡化建構式,可以省去指定泛型類型:
// 靜態泛型函式
public static Tuple<T1, T2> CreateTuple(T1 item1, T2 item2)
{
return new Tuple<T1, T2>(item1, item2);
}
// 泛型建構式
var tuple1 = new Tuple<string, int>("Jack", 18);
var tuple2 = CreateTuple("Jack", 18); // 由於類型推斷, 省去寫泛型型別
3. 類型約束#
public static void SortList<T>(List<T> items) where T : IComparable<T>
{
// 因為限定 T 需要繼承 IComparable, 所以可以叫用其 CompareTo 方法
items.Sort((x,y) => x.CompareTo(y));
}
4. 泛型類型的初始化與狀態#
List<int>
與 List<string>
雖油桐一個泛型類型 List<T>
限定,但在執行期會被當作兩個不同的類型- 範例1. 用 typeof 測試
public static void PrintType<T>()
{
Console.WriteLine($"typeof(T) = {typeof(T)}");
Console.WriteLine($"typeof(List<T>) = {typeof(List<T>)}");
}
public static void Main()
{
PrintType<string>();
PrintType<int>();
}
// typeof(T) = System.String
// typeof(List<T>) = System.Collections.Generic.List`1[System.String]
// typeof(T) = System.Int32
// typeof(List<T>) = System.Collections.Generic.List`1[System.Int32]
- 範例2. 檢查靜態域
class GenericCounter<T>
{
private static int value;
static GenericCounter()
{
Console.WriteLine($"Initializing counter for {typeof(T)}");
}
public static void Increment()
{
value++;
}
public static void Display()
{
Console.WriteLine($"Counter for {typeof(T)}: {value}");
}
}
public static void Main()
{
GenericCounter<string>.Increment();
GenericCounter<string>.Increment();
GenericCounter<string>.Display();
GenericCounter<int>.Display();
GenericCounter<int>.Increment();
GenericCounter<int>.Display();
}
// Initializing counter for System.String
// Counter for System.String: 2
// Initializing counter for System.Int32
// Counter for System.Int32: 0
// Counter for System.Int32: 1