在C#中,HashtableDictionary<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
};

总结

特性HashtableDictionary<TKey, TValue>
类型安全❌ 非泛型✅ 泛型
性能较慢(装箱/拆箱)较快(无装箱)
空键✅ 允许❌ 不允许
空值✅ 允许✅ 允许
线程安全✅ 有同步版本❌ 需要手动同步
推荐程度❌ 遗留代码✅ 新项目首选

建议:在新项目中始终使用 Dictionary<TKey, TValue>,除非有特定的兼容性需求。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐