关于.NET:为什么在C#中字典比哈希表更受欢迎?

Why is Dictionary preferred over Hashtable in C#?

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


就其价值而言,字典(概念上)是一个哈希表。

如果您的意思是"为什么我们要使用Dictionary类而不是Hashtable类?"这是一个简单的答案:Dictionary是一个通用类型,Hashtable不是。这意味着您可以使用Dictionary获得类型安全性,因为您不能在其中插入任何随机对象,也不必强制转换所取的值。

有趣的是,.NET框架中的Dictionary实现是基于Hashtable的,正如您在其源代码中看到的注释所示:

The generic Dictionary was copied from Hashtable's source

来源


Dictionary<<<>Hashtable差异:

  • 通用的<<<>非通用
  • 线程同步的需要自己的<<><Synchronized()提供线程安全版本的方法,通
  • enumerated项目:KeyValuePair<<<>enumerated DictionaryEntry项目:
  • 新的(.net 2.0<><>)大(由于.NET 1.0)
  • 在system.collections.generic<<<一>是集合系统。
  • 现有的密钥请求不抛出异常的<<<>非现有的密钥请求到返回null
  • 值类型是潜在的更快的比特位的<<<>慢(需要装箱/拆箱值类型)

Dictionary/ Hashtable相似:

  • 无论是散列表=式快速访问关键数据,根据多个项目
  • 独特的键和两个不变的需要
  • GetHashCode()都需要自己的方法。

NET集合(类似的候选人而不是使用字典和哈希表):

  • ConcurrentDictionary线程安全的(可以从几个线程安全的访问concurrently)
  • HybridDictionary优化性能(在一些项目,也被许多项目)
  • OrderedDictionary值可以通过数组索引(访问),在这项命令,分别。
  • 自动SortedDictionary项目类
  • 强型和优化StringDictionary弦乐


因为Dictionary是一个通用类(Dictionary),所以访问它的内容是类型安全的(即,您不需要像处理Hashtable那样从Object强制转换)。

比较

1
2
3
var customers = new Dictionary<string, Customer>();
...
Customer customer = customers["Ali G"];

1
2
3
var customers = new Hashtable();
...
Customer customer = customers["Ali G"] as Customer;

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


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

因此,我们不得不把所有的词典都改回Hashtable


在.NET中,Dictionary<,>Hashtable的区别主要在于前者是一个通用类型,因此您可以从静态类型检查(和简化装箱)方面获得通用类型的所有好处,但这并不像人们通常认为的性能那样大,尽管装箱有一定的内存成本。


人们说字典和哈希表是一样的。

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

您同样可以使用链接列表或搜索树来实现一个字典,但它并没有那么有效(对于某些有效的度量标准而言)。


Collections&;Generics是有用的在处理组中的对象。NET中的所有对象的集合,是在IEnumerable接口,进而有ArrayList(Index-Value))&;HashTable(Key-Value)。在.NET Framework 2.0,ArrayList&;Hashtable被替换与List&;Dictionary。现在,ArrayList&;Hashtable是更多的用在当前的项目。

之间的差分来Hashtable&;DictionaryDictionary是通用的,在Hastable是不通用的。我们可以添加到任何类型的对象,而Hashtable查询,但我们需要它的铸造所需的类型。操作系统,它是不安全的类型。但到Dictionarydeclaring本身,而我们可以指定键和值的类型,因此,在铸造时是要检索。

让我们看一个例子:

哈希表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
        }

    }
}

词典

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
        }
    }
}


字典:

  • 如果我们试图找到一个不存在的键,它将返回/引发异常。

  • 它比哈希表快,因为没有装箱和拆箱。

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

  • 字典是一个通用类型,这意味着我们可以将它与任何数据类型一起使用(创建时,必须同时为键和值指定数据类型)。

    示例:Dictionary =
    new Dictionary();

  • dictionary是hashtable的类型安全实现,KeysValues是强类型的。

Hashtable:

  • 如果我们试图找到一个不存在的键,它将返回空值。

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

  • 哈希表中的所有成员都是线程安全的,

  • 哈希表不是泛型类型,

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


使用关于msdn的C文章对数据结构进行的广泛检查表明,碰撞解决策略也存在差异:

hashtable类使用一种称为rehashing的技术。

Rehashing works as follows: there is a set of hash different functions,
H1 ... Hn, and when inserting or retrieving an item from the hash
table, initially the H1 hash function is used. If this leads to a
collision, H2 is tried instead, and onwards up to Hn if needed.

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

With rehashing, in the event of a collision the hash is recomputed, and the new slot corresponding to a hash is tried. With chaining, however, a secondary data structure is utilized to hold
any collisions. Specifically, each slot in the Dictionary has an array
of elements that map to that bucket. In the event of a collision, the
colliding element is prepended to the bucket's list.


NET框架3.5,因为这也将有一个HashSet提供所有可能需要的,如果你只有Dictionary键和值。

如果你使用的操作系统Dictionary永远设置值到null到simulate型安全哈希表应该考虑到你可能HashSet开关。


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


注意,msdn说:"dictionary<(of<(tkey,tvalue>)>)类被实现为哈希表",而不是"dictionary<(of<(tkey,tvalue>)>)类被实现为哈希表"。

字典不是作为哈希表实现的,但它是按照哈希表的概念实现的。由于使用了泛型,实现与hashtable类无关,尽管在内部,Microsoft可以使用相同的代码,并用tkey和tvalue替换object类型的符号。

在.NET 1.0中,不存在泛型;这是哈希表和ArrayList最初开始的地方。


HashTable:

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

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

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

字典:哈希表的通用变量。

禁止装箱/拆箱。不需要转换。


该桶是由哈希表对象包含的元素的集合。只要是一个水桶在哈希表中的虚拟元件,这使得更容易和更快的检索和检索比在大多数系列。

该词典具有相同功能的类的类的类。一本字典的特异型(有更好的表现比其他对象)是比哈希表哈希表元素的值类型是因为研究对象和类型,因此,装箱和拆箱typically发生如果储存或检索价值的类型。

进一步的阅读和词典:哈希表的集合类型


我能理解的另一个区别是:

我们不能在Web服务中使用字典。原因是没有Web服务标准支持泛型标准。


Dictionary<>是通用型操作系统和它的类型安全。

你可以插入任何类型的哈希表中的值,这可能会抛异常。但Dictionary将只接受整数的值和Dictionary同样将只接受字符串。

操作系统,它是更好的使用HashtableDictionary<>代替。


另一个重要的区别是哈希表是线程安全的。hashtable具有内置的多个读卡器/单编写器(mr/sw)线程安全性,这意味着hashtable允许一个编写器与多个读卡器一起使用而不进行锁定。

对于字典,没有线程安全;如果需要线程安全,必须实现自己的同步。

进一步阐述:

Hashtable provides some thread-safety through the Synchronized property, which returns a thread-safe wrapper around the collection. The wrapper works by locking the entire collection on every add or remove operation. Therefore, each thread that is attempting to access the collection must wait for its turn to take the one lock. This is not scalable and can cause significant performance degradation for large collections. Also, the design is not completely protected from race conditions.

The .NET Framework 2.0 collection classes like List, Dictionary, etc. do not provide any thread synchronization; user code must provide all synchronization when items are added or removed on multiple threads concurrently

如果需要类型安全和线程安全,请使用.NET框架中的并发集合类。进一步阅读。

另外一个区别是,当我们在字典中添加多个条目时,条目的添加顺序是保持不变的。当我们从字典中检索条目时,我们将按照插入它们的相同顺序获取记录。而hashtable不保留插入顺序。


In most programming languages, dictionaries are preferred over hashtables

我不认为这是必然的,大多数语言都有一种或另一种,这取决于他们喜欢的术语。

然而,在C中,(对我来说)明显的原因是C哈希表和System.Collections命名空间的其他成员基本上已过时。它们出现在C v1.1中。它们已被System.Collections.Generic命名空间中的泛型类从C_2.0替换。


根据我使用.NET Reflector看到的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[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在内部使用哈希表。