C#中的Hashtable和Dictionary<TKey, TValue>
·
在C#中,Hashtable和Dictionary<TKey, TValue>都是键值对集合,但它们有重要区别:
1. 类型安全性
Hashtable (非泛型)
Hashtable hashtable = new Hashtable();
hashtable.Add("key1", "value1");
hashtable.Add(123, 456); // 可以混合类型
hashtable.Add(3.14, true);
// 取值需要类型转换
string value = (string)hashtable["key1"]; // 需要显式转换
// 可能抛出 InvalidCastException
Dictionary<TKey, TValue> (泛型)
Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary.Add("key1", 100);
dictionary.Add("key2", 200);
// dictionary.Add(123, 300); // 编译错误:类型不匹配
// 直接获取类型安全的值
int value = dictionary["key1"]; // 不需要转换
2. 性能对比
Hashtable
- 装箱/拆箱开销:值类型需要装箱
- 稍慢:由于类型检查和转换
Dictionary<TKey, TValue>
- 无装箱开销:类型在编译时确定
- 更快:直接访问,无转换开销
// 性能测试示例
var stopwatch = Stopwatch.StartNew();
Hashtable ht = new Hashtable();
for (int i = 0; i < 1000000; i++)
{
ht.Add(i, i); // 装箱发生在这里
int value = (int)ht[i]; // 拆箱发生在这里
}
var dictStopwatch = Stopwatch.StartNew();
Dictionary<int, int> dict = new Dictionary<int, int>();
for (int i = 0; i < 1000000; i++)
{
dict.Add(i, i); // 无装箱
int value = dict[i]; // 无拆箱
}
3. 空值处理
Hashtable
Hashtable ht = new Hashtable();
ht.Add("key1", null); // 允许空值
ht.Add(null, "value"); // 允许空键
Dictionary<TKey, TValue>
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("key1", null); // 允许空值(如果TValue是引用类型)
// dict.Add(null, "value"); // 运行时异常:键不能为null
4. 线程安全性
Hashtable
Hashtable synchronizedHT = Hashtable.Synchronized(new Hashtable());
// 提供线程安全的包装器
Dictionary<TKey, TValue>
Dictionary<string, string> dict = new Dictionary<string, string>();
// 非线程安全,需要手动同步
lock (dict)
{
dict.Add("key", "value");
}
// 或者使用 ConcurrentDictionary
ConcurrentDictionary<string, string> concurrentDict = new ConcurrentDictionary<string, string>();
5. 方法对比
共同方法
// 两者都有的方法
hashtable.Add(key, value);
dictionary.Add(key, value);
hashtable.Remove(key);
dictionary.Remove(key);
hashtable.Contains(key);
dictionary.ContainsKey(key);
hashtable.Clear();
dictionary.Clear();
特有方法
// Dictionary特有的
if (dictionary.TryGetValue("key", out int value))
{
// 安全获取值
}
// 获取键或值的集合
var keys = dictionary.Keys;
var values = dictionary.Values;
6. 迭代方式
Hashtable
foreach (DictionaryEntry entry in hashtable)
{
Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}");
}
// 或者
foreach (object key in hashtable.Keys)
{
object value = hashtable[key];
}
Dictionary<TKey, TValue>
foreach (KeyValuePair<string, int> kvp in dictionary)
{
Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
}
// 或者只遍历键或值
foreach (string key in dictionary.Keys)
{
// 处理键
}
7. 使用场景
Hashtable 适用场景:
- 需要与遗留代码交互
- 需要存储混合类型的数据
- 需要空键支持
- 需要内置的线程安全版本
Dictionary<TKey, TValue> 适用场景:
- 新开发项目(推荐)
- 性能敏感的应用
- 类型安全重要的场景
- 大多数现代C#应用程序
8. 实际示例
配置存储
// 使用 Dictionary(推荐)
Dictionary<string, object> config = new Dictionary<string, object>
{
["Timeout"] = 30,
["Server"] = "localhost",
["Enabled"] = true
};
// 使用 Hashtable(传统方式)
Hashtable legacyConfig = new Hashtable
{
["Timeout"] = 30,
["Server"] = "localhost",
["Enabled"] = true
};
总结
| 特性 | Hashtable | Dictionary<TKey, TValue> |
|---|---|---|
| 类型安全 | ❌ 非泛型 | ✅ 泛型 |
| 性能 | 较慢(装箱/拆箱) | 较快(无装箱) |
| 空键 | ✅ 允许 | ❌ 不允许 |
| 空值 | ✅ 允许 | ✅ 允许 |
| 线程安全 | ✅ 有同步版本 | ❌ 需要手动同步 |
| 推荐程度 | ❌ 遗留代码 | ✅ 新项目首选 |
建议:在新项目中始终使用 Dictionary<TKey, TValue>,除非有特定的兼容性需求。
更多推荐


所有评论(0)