本文涵蓋兩個實用主題:(1) Dictionary 迴圈時使用 KeyValuePair 避免 boxing、強型別存取;(2) where T : constraint 限制型別參數必須實作介面、繼承類別、為值/參考型別、有無參建構子。
var dict = new Dictionary { {1, "Foo"}, {2, "Bar"}, {3, "Baz"} };
// 推薦:強型別、無 boxing
foreach (var kvp in dict)
{
Console.WriteLine($"Key={kvp.Key}, Value={kvp.Value}");
}
// 非泛型 Hashtable 只能用 DictionaryEntry(需 unboxing)
foreach (DictionaryEntry de in (IDictionary)dict) { /* de.Key, de.Value 為 object */ }
優勢:KeyValuePair 為結構體、直接包含強型別 Key/Value,效能優於 DictionaryEntry(reference type、需 unboxing)。
// 必須實作 IDisposable
public class DisposableList : IList where T : IDisposable
{
private List _items = new List();
private void Delete(T item) => item.Dispose(); // 編譯期保證有 Dispose()
}
// 必須繼承 TextReader 且實作 IDisposable
public class ReaderList where T : TextReader, IDisposable { }
// 必須為值型別
public class StructList where T : struct { }
// 必須為參考型別
public class ClassList where T : class { }
// 必須有 public 無參建構子
public class CreatableList where T : new() { }
// 組合約束
public class ComplexList where T : class, IDisposable, new() { }
DisposableList 直接編譯錯誤(string 不實作 IDisposable)。item.Dispose()、new T()、(T)someObject 等,無需反射或動態轉型。| 約束 | 語法 | 適用場景 |
|---|---|---|
| 介面 | where T : IInterface | 需呼叫介面方法 |
| 基底類別 | where T : BaseClass | 需存取基底成員 |
| 值型別 | where T : struct | 避免 boxing、堆疊分配 |
| 參考型別 | where T : class | 需為 null、繼承、介面轉型 |
| 無參建構子 | where T : new() | 工廠模式、Activator.CreateInstance 替代 |
| 非受控型別 | where T : unmanaged | C# 7.3+,可用 sizeof、指標、Stackalloc |
| 委派 | where T : Delegate | C# 7.3+,MulticastDelegate 亦可 |
| Enum | where T : Enum | C# 7.3+,泛型 Enum 旗標操作 |
where T : string)、運算子、靜態方法、屬性。class Pair where TKey : IComparable where TValue : new() 。class 約束(參考型別),可加 struct 允許值型別實作介面。善用 KeyValuePair 迭代與 where 約束,能寫出既高效又具自我文件化的泛型程式碼。