为何在 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/