本文介紹兩項泛型實務技巧:(1) 使用 ReadOnlyCollection 包裝內部清單對外暴露唯讀視圖;(2) 以 Dictionary 完整取代 Hashtable,消除 boxing、強型別、效能提升,並對照兩者成員對應表。
public class Lottery
{
private List _numbers = new List { 17, 21, 32, 44, 58 };
public ReadOnlyCollection Results => new ReadOnlyCollection(_numbers);
}
// 使用
var lottery = new Lottery();
foreach (var n in lottery.Results) Console.WriteLine(n);
// lottery.Results[0] = 99; // 編譯錯誤:唯讀
優點:建構子接受任何 IList、陣列,零複製成本(包裝器模式)、標準化唯讀回傳型別、防止外部修改內部狀態。
| Hashtable 成員 | Dictionary 對應 | 備註 |
|---|---|---|
| Count | Count | |
| Keys / Values | Keys / Values | 回傳 ICollection 而非 ICollection |
| Item[key] | this[key] | 強型別 Key/Value |
| Add/Remove/Clear | Add/Remove/Clear | |
| Contains(key) | ContainsKey(key) | Hashtable.Contains 等同 ContainsKey |
| ContainsValue | ContainsValue | |
| Clone() | new Dictionary(dict) | 複製建構子替代 ICloneable |
| CopyTo | ((ICollection)dict).CopyTo(arr,0) | 需轉介面,目標陣列為 KeyValuePair[] |
| IsSynchronized/SyncRoot | lock(dict) / lock(((ICollection)dict).SyncRoot) | 泛型集合移除同步包裝,建議自行 lock |
| Synchronized() | 無 | 改用 ConcurrentDictionary 或自行 lock |
| TryGetValue | TryGetValue | Dictionary 獨有,避免雙次查找 |
// Hashtable: boxing/unboxing 發生在 key (int) 與 value (string) 皆為值型別時
Hashtable ht = new Hashtable(); ht.Add(1, "one"); // key 裝箱
foreach (DictionaryEntry de in ht) { int k = (int)de.Key; string v = (string)de.Value; } // 解箱
// Dictionary: 零 boxing
var dict = new Dictionary(); dict.Add(1, "one");
foreach (var kvp in dict) { int k = kvp.Key; string v = kvp.Value; } // 直接強型別
IsFixedSize、IsReadOnly、IsSynchronized、SyncRoot:轉 IDictionary 介面存取 ((IDictionary)dict).IsReadOnly。Clone:使用複製建構子 new Dictionary(existingDict) 。CopyTo:目標陣列宣告為 KeyValuePair[] ,轉 ICollection 呼叫。對 100 萬筆 int→string 寫入/讀取,Dictionary 比 Hashtable 快 2-3 倍,記憶體減少 30%+(無 boxing 物件)。
全面改用 Dictionary、List、Queue、Stack、ReadOnlyCollection,是 .NET 2.0+ 專案的基本功。