为什么Dictionary优先于C#中的Hashtable?

时间:2008-11-19 09:24:25

标签: c# .net vb.net data-structures

在大多数编程语言中,字典比哈希表更受欢迎。 这背后的原因是什么?

19 个答案:

答案 0 :(得分:1497)

对于它的价值,词典 (概念上)是一个哈希表。

如果您的意思是“为什么我们使用Dictionary<TKey, TValue>类而不是Hashtable类?”,那么这是一个简单的答案:Dictionary<TKey, TValue>是泛型类型,{{1} } 不是。这意味着您可以使用Hashtable获得类型安全性,因为您无法在其中插入任何随机对象,并且您不必强制转换所取出的值。

有趣的是,.NET Framework中的Dictionary<TKey, TValue>实现基于Dictionary<TKey, TValue>,您可以从源代码中的注释中看出:

  

通用词典是从Hashtable的源代码

复制而来的

Source

答案 1 :(得分:596)

Dictionary &lt;&lt;&lt;&gt;&gt;&gt; Hashtable 差异:

  • 通用&lt;&lt;&lt;&gt;&gt;&gt;的非通用
  • 需要自己的线程同步&lt;&lt;&lt;&gt;&gt;&gt;通过 Synchronized() 方法
  • 提供线程安全版本
  • 枚举项目: KeyValuePair &lt;&lt;&lt;&gt;&gt;&gt;枚举项目: DictionaryEntry
  • 较新(&gt; .NET 2.0 )&lt;&lt;&lt;&gt;&gt;&gt;较旧(因为 .NET 1.0
  • 位于 System.Collections.Generic &lt;&lt;&lt;&gt;&gt;&gt;在 System.Collections
  • 请求不存在的密钥抛出异常&lt;&lt;&lt;&gt;&gt;&gt;请求不存在的密钥返回null
  • 对于值类型可能有点更快&lt;&lt;&lt;&gt;&gt;&gt;值类型慢一点(需要装箱/取消装箱)

Dictionary / Hashtable 相似之处:

  • 两者都是内部哈希表 ==根据密钥快速访问多项数据
  • 两者都需要不可变且唯一的密钥
  • 两者的密钥都需要拥有 GetHashCode() 方法

类似 .NET集合(使用候选而不是Dictionary和Hashtable):

  • ConcurrentDictionary - 线程安全(可以同时从多个线程安全地访问)
  • HybridDictionary - 优化效果(少数项目以及许多项目)
  • OrderedDictionary - 可以通过int index 访问值(按添加项目的顺序)
  • SortedDictionary - 项自动排序
  • StringDictionary - 强类型和为字符串优化

答案 2 :(得分:173)

因为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

但是,{{1}}在内部实现为哈希表,因此从技术上讲它的工作方式相同。

答案 3 :(得分:84)

仅供参考:在.NET中,Hashtable对于多个读取器线程和单个写入线程使用是线程安全的,而在Dictionary中,公共静态成员是线程安全的,但不保证任何实例成员是线程安全的。

由于这个原因,我们不得不将所有字典更改回Hashtable

答案 4 :(得分:67)

在.NET中,Dictionary<,>HashTable之间的区别主要在于前者是泛型类型,因此您可以在静态类型检查方面获得泛型的所有好处(并减少装箱,但这并不像人们在表现方面所认为的那么大 - 虽然拳击有一定的记忆成本。

答案 5 :(得分:32)

人们说词典与哈希表相同。

这不一定是真的。哈希表是实现字典的一种方法。这是一个典型的,它可能是Dictionary类中.NET中的默认值,但根据定义它不是唯一的。

你同样可以使用链表或搜索树来实现字典,它只是效率不高(对某些效率指标而言)。

答案 6 :(得分:22)

Collections&amp; Generics对于处理对象组很有用。在.NET中,所有集合对象都在接口IEnumerable下面,而ArrayList(Index-Value))接口HashTable(Key-Value)&amp; ArrayList。在.NET framework 2.0之后,HashTable&amp;已将List替换为Dictionary&amp; Arraylist。现在,HashTable&amp; HashTable在现今的项目中不再使用。

Dictionary&amp;之间的区别DictionaryHastable是通用的,因为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);
        }
    }
}

<强>词典,

{{1}}

答案 7 :(得分:16)

<强>词典:

  • 如果我们试图找到一个不存在的密钥,它会返回/抛出异常。

  • 它比Hashtable更快,因为没有装箱和拆箱。

  • 只有公共静态成员是线程安全的。

  • Dictionary是一种泛型类型,这意味着我们可以将它与任何数据类型一起使用(创建时,必须指定键和值的数据类型)。

    示例:Dictionary<string, string> <NameOfDictionaryVar> = new Dictionary<string, string>();

  • Dictionay是Hashtable的类型安全实现,KeysValues是强类型的。

<强>哈希表

  • 如果我们尝试查找不存在的密钥,则返回null。

  • 它比字典慢,因为它需要装箱和拆箱。

  • Hashtable中的所有成员都是线程安全的,

  • Hashtable不是通用类型,

  • Hashtable是松散类型的数据结构,我们可以添加任何类型的键和值。

答案 8 :(得分:15)

MSDN上的Extensive Examination of Data Structures Using C#文章指出冲突解决策略也存在差异:

Hashtable类使用称为 rehashing 的技术。

  

Rehashing的工作方式如下:有一组哈希不同的函数,   H 1 ... H n ,以及从哈希中插入或检索项目时   表,最初使用H 1 哈希函数。如果这导致了   如果需要,尝试碰撞,H 2 ,然后再转到H n

字典使用称为链接的技术。

  

通过重新散列,在发生冲突时,重新计算散列,并尝试对应于散列的新槽。然而,通过链接,利用二级数据结构来保持   任何碰撞。具体来说,Dictionary中的每个插槽都有一个数组   映射到该存储桶的元素。在发生碰撞时,   碰撞元素被添加到存储桶列表中。

答案 9 :(得分:14)

自.NET Framework 3.5起,还有一个HashSet<T>,如果您只需要键而没有值,则会提供Dictionary<TKey, TValue>的所有专业人员。

因此,如果您使用Dictionary<MyType, object>并始终将值设置为null来模拟类型安全哈希表,则应考虑切换到HashSet<T>

答案 10 :(得分:12)

Hashtable是一种松散类型的数据结构,因此您可以将任意类型的键和值添加到HashtableDictionary类是类型安全的Hashtable实现,键和值是强类型的。创建Dictionary实例时,必须为键和值指定数据类型。

答案 11 :(得分:11)

请注意,MSDN说:“Dictionary&lt;(Of&lt;(TKey,TValue&gt;)&gt;)类实现为哈希表”,而不是“Dictionary&lt;(Of&lt;(TKey) ,TValue&gt;)&gt;)类实现为 HashTable

Dictionary不是作为HashTable实现的,而是按照哈希表的概念实现的。由于使用了泛型,实现与HashTable类无关,尽管内部Microsoft可能使用了相同的代码并用TKey和TValue替换了Object类型的符号。

在.NET 1.0中,Generics不存在;这是HashTable和ArrayList最初开始的地方。

答案 12 :(得分:8)

Hashtable对象由包含集合元素的存储桶组成。存储桶是Hashtable中虚拟的元素子组,这使得搜索和检索比大多数集合更容易,更快

Dictionary类具有与Hashtable类相同的功能。特定类型的字典(除了Object)对于值类型具有比Hashtable 更好的性能,因为Hashtable的元素是Object类型,因此,如果存储或检索a,则通常会发生装箱和取消装箱。价值类型。

进一步阅读:Hashtable and Dictionary Collection Types

答案 13 :(得分:8)

<强>哈希表

键/值将在存储到堆中时转换为对象(装箱)类型。

在从堆中读取时,需要将键/值转换为所需类型。

这些操作非常昂贵。我们需要尽可能避免装箱/拆箱。

字典: HashTable的通用变体。

没有拳击/拆箱。无需转换。

答案 14 :(得分:6)

我能想出的另一个不同之处是:

我们不能使用Dictionary&lt; KT,VT&gt; (泛型)与Web服务。原因是没有Web服务标准支持泛型标准。

答案 15 :(得分:6)

Dictionary<>是一种通用类型,所以它的类型是安全的。

您可以在HashTable中插入任何值类型,这有时会引发异常。但Dictionary<int>只接受整数值,同样Dictionary<string>只会接受字符串。

因此,最好使用Dictionary<>代替HashTable

答案 16 :(得分:6)

另一个重要的区别是Hashtable是线程安全的。 Hashtable内置多个读取器/单个写入器(MR / SW)线程安全,这意味着Hashtable允许一个编写器与多个读取器一起使用而无需锁定。

在Dictionary的情况下,没有线程安全;如果您需要线程安全,则必须实现自己的同步。

进一步阐述:

  

Hashtable通过Synchronized属性提供一些线程安全性,该属性返回集合周围的线程安全包装器。包装器通过在每次添加或删除操作时锁定整个集合来工作。因此,尝试访问集合的每个线程必须等待轮到一个锁。这不可扩展,可能会导致大型集合的性能显着下降。此外,该设计并未完全免受竞争条件的影响。

     

.NET Framework 2.0集合类(如List<T>, Dictionary<TKey, TValue>等)不提供任何线程同步;用户代码必须在多个线程上同时添加或删除项目时提供所有同步

如果您需要类型安全性以及线程安全性,请在.NET Framework中使用并发集合类。进一步阅读here

另一个区别是,当我们在Dictionary中添加多个条目时,将保留添加条目的顺序。当我们从Dictionary中检索项目时,我们将按照插入它们的相同顺序获取记录。 Hashtable并不保留插入顺序。

答案 17 :(得分:0)

  

在大多数编程语言中,字典比哈希表更受欢迎

我认为这不一定是正确的,大多数语言都有一种或另一种语言,具体取决于terminology they prefer

但是,在C#中,(对我而言)显而易见的原因是C#HashTables和System.Collections命名空间的其他成员已经过时了。它们存在于c#V1.1中。它们已从C#2.0中被System.Collections.Generic命名空间中的Generic类替换。

答案 18 :(得分:-3)

根据我使用.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。