提问人:Nakul Chaudhary 提问时间:11/19/2008 最后编辑:kristianpNakul Chaudhary 更新时间:10/25/2021 访问量:600229
为什么在 C# 中 Dictionary 优于 Hashtable?
Why is Dictionary preferred over Hashtable in C#?
答:
因为是一个泛型类 ( ),因此访问其内容是类型安全的(即您不需要像使用 )。Dictionary
Dictionary<TKey, TValue>
Object
Hashtable
比较
var customers = new Dictionary<string, Customer>();
...
Customer customer = customers["Ali G"];
自
var customers = new Hashtable();
...
Customer customer = customers["Ali G"] as Customer;
但是,在内部实现为哈希表,因此从技术上讲,它的工作方式相同。Dictionary
在 .NET 中,和之间的区别主要在于前者是泛型类型,因此在静态类型检查方面可以获得泛型的所有好处(并减少了装箱,但这并不像人们在性能方面倾向于认为的那么大 - 不过,装箱有一定的内存成本)。Dictionary<,>
HashTable
是松散类型的数据结构,因此您可以向 .该类是类型安全的实现,键和值是强类型的。创建实例时,必须同时指定键和值的数据类型。Hashtable
Hashtable
Dictionary
Hashtable
Dictionary
就其价值而言,字典(从概念上讲)是一个哈希表。
如果你的意思是“为什么我们使用类而不是类?”,那么这是一个简单的答案:是泛型类型,不是。这意味着你可以用 获得类型安全,因为你不能在其中插入任何随机对象,也不必强制转换你取出的值。Dictionary<TKey, TValue>
Hashtable
Dictionary<TKey, TValue>
Hashtable
Dictionary<TKey, TValue>
有趣的是,.NET Framework 中的实现基于 ,从源代码中的注释中可以看出:Dictionary<TKey, TValue>
Hashtable
通用字典是从 Hashtable 的源代码复制而来的
评论
HashTable
Dictionary
HashTable
Dictionary
Dictionary
HashTable
Dictionary<Object,Object>
HashTable
仅供参考:在 .NET 中,线程安全供多个读取器线程和一个写入线程使用,而在公共中,静态成员是线程安全的,但不能保证任何实例成员都是线程安全的。Hashtable
Dictionary
因此,我们不得不将所有词典改回原来的字典。Hashtable
评论
ConcurrentDictionary
Hashtable
人们说字典和哈希表是一样的。
这不一定是真的。哈希表是实现字典的一种方法。一个典型的,它可能是类中 .NET 中的默认一个,但根据定义,它不是唯一的一个。Dictionary
你同样可以使用链表或搜索树来实现字典,只是效率不高(对于某些效率指标)。
评论
Dictionary<K,V>
IDictionary<K,V>
我能弄清楚的另一个区别是:
我们不能将 Dictionary<KT,VT>(泛型)用于 Web 服务。原因是没有 Web 服务标准支持泛型标准。
评论
请注意,文档说:“Dictionary<(Of <(TKey, TValue>)>) 类是作为哈希表实现的”,而不是“Dictionary<(Of <(TKey, TValue>)>) 类是作为 HashTable 实现的"
Dictionary 不是作为 HashTable 实现的,而是按照哈希表的概念实现的。由于使用了泛型,该实现与 HashTable 类无关,尽管 Microsoft 内部可以使用相同的代码并将 Object 类型的符号替换为 TKey 和 TValue。
在 .NET 1.0 中,泛型不存在;这是 HashTable 和 ArrayList 最初开始的地方。
根据我使用 .NET Reflector 所看到的:
[Serializable, ComVisible(true)]
public abstract class DictionaryBase : IDictionary, ICollection, IEnumerable
{
// Fields
private Hashtable hashtable;
// Methods
protected DictionaryBase();
public void Clear();
.
.
.
}
Take note of these lines
// Fields
private Hashtable hashtable;
因此,我们可以确定 DictionaryBase 在内部使用了 HashTable。
评论
差异
Dictionary |
Hashtable |
---|---|
通用 | 非通用 |
需要自己的线程同步 | 通过 Synchronized() 方法提供线程安全版本 |
枚举项:KeyValuePair |
枚举项:DictionaryEntry |
较新的 (> .NET 2.0) | 较旧(自 .NET 1.0 起)) |
位于 System.Collections.Generic 中 | 位于 System.Collections 中 |
对不存在的密钥的请求引发异常 | 对不存在的键的请求返回 null |
对于值类型,可能会更快一些 | 值类型稍慢(需要装箱/取消装箱) |
相似 之 处:
- 两者都是内部哈希表 == 根据键快速访问多项目数据
- 两者都需要不可变且唯一的密钥
- 两者的键都需要自己的
GetHashCode()
方法
备用 .NET 集合:
(用于代替 Dictionary 和 Hashtable 的候选者)
ConcurrentDictionary
- 线程安全(可以同时从多个线程安全地访问)HybridDictionary
- 优化性能(针对少数项目和许多项目)OrderedDictionary
- 可以通过 int 索引访问值(按添加项的顺序)SortedDictionary
- 项目自动排序StringDictionary
- 强类型并针对字符串进行了优化(现已弃用,取而代之的是 Dictionary<string,string>)
评论
StringDictionary
StringDictionary
Dictionary<string, string>
StringDictionary
现在被认为已过时,取而代之的是具有合适实例的 *Dictionary<string,string>
StringComparer
Dictionary<>
是泛型类型,因此它是类型安全的。
您可以在 HashTable 中插入任何值类型,这有时可能会引发异常。但只接受整数值,同样也只接受字符串。Dictionary<int>
Dictionary<string>
因此,最好使用而不是 .Dictionary<>
HashTable
Collections
& Generics
对于处理对象组很有用。在 .NET 中,所有集合对象都位于接口下,而接口又具有 & 。在 .NET Framework 2.0 之后,& 被替换为 &。现在,&在当今的项目中不再使用。IEnumerable
ArrayList(Index-Value))
HashTable(Key-Value)
ArrayList
HashTable
List
Dictionary
Arraylist
HashTable
谈到 & 之间的区别,是通用的,而 as 不是通用的。我们可以向 添加任何类型的对象,但在检索时,我们需要将其转换为所需的类型。因此,它不是类型安全的。但是要 ,在声明自身的同时,我们可以指定键和值的类型,因此在检索时无需强制转换。HashTable
Dictionary
Dictionary
Hastable
HashTable
dictionary
让我们看一个例子:
哈希表
class HashTableProgram
{
static void Main(string[] args)
{
Hashtable ht = new Hashtable();
ht.Add(1, "One");
ht.Add(2, "Two");
ht.Add(3, "Three");
foreach (DictionaryEntry de in ht)
{
int Key = (int)de.Key; //Casting
string value = de.Value.ToString(); //Casting
Console.WriteLine(Key + " " + value);
}
}
}
字典
class DictionaryProgram
{
static void Main(string[] args)
{
Dictionary<int, string> dt = new Dictionary<int, string>();
dt.Add(1, "One");
dt.Add(2, "Two");
dt.Add(3, "Three");
foreach (KeyValuePair<int, String> kv in dt)
{
Console.WriteLine(kv.Key + " " + kv.Value);
}
}
}
评论
从 .NET Framework 3.5 开始,还有一个 HashSet<T
>它提供了 Dictionary<TKey、TValue
的所有优点>如果您只需要键而不需要值。
因此,如果您使用 并且始终将值设置为 来模拟类型安全哈希表,您可能应该考虑切换到 HashSet<T>
。Dictionary<MyType, object>
null
Hashtable 对象由包含集合元素的存储桶组成。存储桶是 Hashtable 中元素的虚拟子组,与大多数集合相比,它使搜索和检索更容易、更快捷。
Dictionary 类具有与 Hashtable 类相同的功能。对于值类型,特定类型(Object 除外)的 Dictionary 比 Hashtable 具有更好的性能,因为 Hashtable 的元素属于 Object 类型,因此,在存储或检索值类型时,通常会发生装箱和取消装箱。
进一步阅读:哈希表和字典集合类型
字典:
如果我们尝试查找不存在的键,它会返回/抛出异常。
它比 Hashtable 更快,因为没有装箱和拆箱。
只有公共静态成员是线程安全的。
Dictionary 是一种泛型类型,这意味着我们可以将它与任何数据类型一起使用(创建时,必须指定键和值的数据类型)。
例:
Dictionary<string, string> <NameOfDictionaryVar> = new Dictionary<string, string>();
Dictionay 是 Hashtable 的类型安全实现,并且是强类型的。
Keys
Values
哈希表:
如果我们尝试查找不存在的键,它将返回 null。
它比字典慢,因为它需要装箱和解箱。
Hashtable 中的所有成员都是线程安全的,
Hashtable 不是泛型类型,
Hashtable 是松散类型的数据结构,我们可以添加任何类型的键和值。
评论
Dictionary.TryGetValue
MSDN 上的 Extensive Examination of Data Structures Using C# 一文指出,冲突解决策略也存在差异:
Hashtable 类使用一种称为重新散列的技术。
重新散列的工作原理如下:有一组散列不同的函数, H1 ...Hn,以及从哈希中插入或检索项目时 表,最初使用 H1 哈希函数。如果这会导致 碰撞,则尝试 H2,如果需要,可以继续到 Hn。
字典使用一种称为链接的技术。
通过重新散列,在发生冲突时,将重新计算哈希值,并尝试与哈希对应的新槽。然而,通过链接,使用辅助数据结构来保存 任何碰撞。具体来说,字典中的每个插槽都有一个数组 映射到该存储桶的元素。如果发生碰撞, 碰撞元素将追加到存储桶列表的前面。
另一个重要的区别是 Hashtable 是线程安全的。Hashtable 具有内置的多读取器/单写入器 (MR/SW) 线程安全,这意味着 Hashtable 允许一个写入器与多个读取器一起使用而不会锁定。
在 Dictionary 的情况下,没有线程安全;如果需要线程安全,则必须实现自己的同步。
进一步阐述:
Hashtable 通过属性提供一些线程安全,该属性在集合周围返回线程安全包装器。包装器的工作原理是在每次添加或删除操作时锁定整个集合。因此,尝试访问集合的每个线程都必须等待轮到它来获取一个锁。这是不可缩放的,并且可能会导致大型集合的性能显著下降。此外,该设计并未完全受到竞争条件的影响。
Synchronized
.NET Framework 2.0 集合类(如 等)不提供任何线程同步;在多个线程上同时添加或删除项时,用户代码必须提供所有同步
List<T>, Dictionary<TKey, TValue>
如果需要类型安全和线程安全,请在 .NET Framework 中使用并发集合类。进一步阅读 这里.
另一个区别是,当我们在 Dictionary 中添加多个条目时,条目的添加顺序保持不变。当我们从 Dictionary 中检索项目时,我们将按照插入记录的相同顺序获取记录。而 Hashtable 不保留广告订单。
评论
Hashset
Dictionary
哈希表:
键/值在存储到堆中时将转换为对象(装箱)类型。
从堆中读取时,需要将键/值转换为所需的类型。
这些操作的成本非常高。我们需要尽可能避免装箱/拆箱。
字典:HashTable 的泛型变体。
没有装箱/拆箱。无需转换。
在大多数编程语言中,字典比哈希表更受欢迎
我不认为这一定是真的,大多数语言都有这样或那样,这取决于他们喜欢的术语。
然而,在 C# 中,明确的原因(对我来说)是 C# HashTables 和 System.Collections 命名空间的其他成员在很大程度上已经过时了。它们存在于 c# V1.1 中。它们已从 C# 2.0 替换为 System.Collections.Generic 命名空间中的 Generic 类。
评论
Dictionary
Hashtable
HashTable