为何在 C# 中更倾向使用 Dictionary 而非 Hashtable
为何在 C# 中更倾向使用 Dictionary 而非 Hashtable
技术背景
在 C# 开发里,Dictionary<TKey, TValue> 和 Hashtable 都是用于存储键值对的数据结构,其内部均为哈希表,可依据键快速访问数据。不过,由于本质上 Dictionary<TKey, TValue> 是泛型类型,而 Hashtable 是非泛型类型,这使得它们在性能、类型安全性等方面存在诸多差异。
实现步骤
Dictionary 示例代码
1 | |
Hashtable 示例代码
1 | |
差异对比
1. 泛型与否
Dictionary为泛型类型,创建时需指定键和值的类型,从而确保在访问内容时类型安全。Hashtable属于非泛型类型,会将键和值当作Object类型处理,因此在使用时可能需要进行类型转换。
2. 线程安全
Dictionary需要自行实现线程同步。Hashtable借助Synchronized()方法提供线程安全版本。
3. 枚举项
Dictionary枚举项为KeyValuePair。Hashtable枚举项是DictionaryEntry。
4. 版本与命名空间
Dictionary是较新的类(.NET 2.0及以上),位于System.Collections.Generic命名空间。Hashtable是较旧的类(自.NET 1.0开始),处在System.Collections命名空间。
5. 键不存在时的处理方式
Dictionary对不存在的键进行请求时会抛出异常。Hashtable对不存在的键进行请求时返回null。
6. 值类型性能
Dictionary对于值类型可能会稍快一些。Hashtable对于值类型会稍慢(需要进行装箱/拆箱操作)。
相似点
- 二者内部皆为哈希表,能依据键快速访问多项目数据。
- 都需要不可变且唯一的键。
- 二者的键均需要自身的
GetHashCode()方法。
替代的 .NET 集合
ConcurrentDictionary:线程安全,可由多个线程并发安全访问。HybridDictionary:针对不同数量的项目进行了性能优化。OrderedDictionary:可通过整数索引访问值,按添加顺序排列。SortedDictionary:项会自动排序。StringDictionary:类型安全且针对字符串进行了优化(现在已弃用,推荐使用Dictionary<string, string>)。
碰撞解决策略
Hashtable采用的是再哈希(rehashing)技术。存在一组不同的哈希函数H1 ... Hn,插入或检索项时,最初会使用H1哈希函数,若发生碰撞则尝试H2,依此类推。Dictionary采用的是链地址法(chaining)技术。发生碰撞时,会利用一个辅助数据结构来保存所有碰撞元素。具体而言,Dictionary中的每个槽都有一个元素数组,碰撞时会将碰撞元素添加到该槽的列表头部。
最佳实践
- 若需要类型安全且不考虑线程同步,优先选用
Dictionary。 - 若要线程安全,可选用
Hashtable或者ConcurrentDictionary。 - 若要根据插入顺序访问元素,可使用
OrderedDictionary。
常见问题
1. Dictionary 线程不安全怎么办?
若在多线程环境下使用 Dictionary,则需要自行实现线程同步。也可以使用 ConcurrentDictionary 来替代。
2. Hashtable 的线程安全版本性能如何?
Hashtable 的线程安全版本(通过 Synchronized() 方法)在每次添加或移除操作时都会锁定整个集合,这对大型集合来说可能会导致显著的性能下降,且在设计上并不能完全避免竞态条件。
3. Dictionary 和 Hashtable 对值类型的性能差异是怎样的?
Hashtable 在存储或检索值类型时需要进行装箱/拆箱操作,这会影响其性能。而 Dictionary 对于值类型无需进行装箱/拆箱操作,因此性能可能更好。
为何在 C# 中更倾向使用 Dictionary 而非 Hashtable
https://119291.xyz/posts/why-dictionary-preferred-over-hashtable-in-csharp/