ความแตกต่างหลัก
| คุณสมบัติ | Hashtable | Dictionary<TKey, TValue> |
|---|---|---|
| Type System | Non-Generic (System.Collections) | Generic (System.Collections.Generic) |
| Key/Value Types | object/object (Any Type) | Strongly Typed (TKey, TValue) |
| Boxing/Unboxing | Yes (Value Types) | No (Generic) |
| Performance | ช้ากว่า (Boxing + Casting) | เร็วกว่า (Type-Safe) |
| Null Key | Allowed (1 Null Key) | Allowed (1 Null Key) |
| Null Value | Allowed | Allowed (Reference Types) |
| Missing Key Access | Return null | Throw KeyNotFoundException |
| Enumeration Order | ไม่รับประกัน (Unordered) | Insertion Order (Since .NET Core 3.0+) |
| Thread Safety | Hashtable.Synchronized() (Legacy) | ไม่ Thread-Safe (ใช้ ConcurrentDictionary) |
ตัวอย่าง Hashtable (Legacy)
using System;
using System.Collections;
Hashtable ht = new Hashtable();
ht.Add("Name", "John");
ht.Add("Age", 30);
ht.Add(1, "Number Key"); // Key/Value สับสน Type ได้
// Access - Return null ถ้าไม่มี Key
object val = ht["Missing"]; // null, ไม่ Throw
// Boxing/Unboxing
ht.Add("Count", 100);
int count = (int)ht["Count"]; // Unbox จำเป็น
foreach (DictionaryEntry entry in ht)
{
Console.WriteLine($"{entry.Key} ({entry.Key.GetType()}) = {entry.Value} ({entry.Value.GetType()})");
}
ตัวอย่าง Dictionary (Modern)
using System;
using System.Collections.Generic;
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("Name", "John");
dict.Add("Age", 30);
// dict.Add(1, "Error"); // ❌ Compile Error: Key ต้องเป็น string
// Access - Throw Exception ถ้าไม่มี Key
// object val = dict["Missing"]; // KeyNotFoundException
// Safe Access
if (dict.TryGetValue("Missing", out object val))
Console.WriteLine(val);
else
Console.WriteLine("Not Found");
// No Boxing for Value Types
Dictionary<string, int> ages = new();
ages.Add("John", 30);
int age = ages["John"]; // Direct, No Cast
Performance Comparison
// Benchmark: 1,000,000 Operations
// Dictionary: ~15ms
// Hashtable: ~45ms (3x Slower due to Boxing)
Migration Guide
// Old Hashtable Code
Hashtable ht = new Hashtable();
ht["key"] = "value";
string v = (string)ht["key"];
// New Dictionary Code
var dict = new Dictionary<string, string>();
dict["key"] = "value";
string v = dict["key"]; // No Cast
// Thread-Safe Version
var concurrent = new ConcurrentDictionary<string, string>();
concurrent.TryAdd("key", "value");
เมื่อไหร่ยังใช้ Hashtable
- Legacy Code (.NET Framework 1.x/2.0)
- COM Interop ที่ต้องการ
IDictionaryNon-Generic - Dynamic Types ที่ Key/Value สลับ Type ได้จริง (Rare)
Hashtable.Synchronized()สำหรับ Simple Thread-Safe (แต่แนะนำ ConcurrentDictionary)
Best Practice
✅ ใช้ Dictionary<TKey, TValue> เสมอสำหรับโค้ดใหม่
- Type Safety, Performance, Readability ดีกว่า
- Hashtable เป็น Legacy (Obsolete ในบาง Context)
- Type Safety, Performance, Readability ดีกว่า
- Hashtable เป็น Legacy (Obsolete ในบาง Context)