In this article, we are going to compare Dictionary and Hashtable in C#. We will start with a brief introduction to both data structures and then proceed to the comparison.

To download the source code for this article, you can visit our GitHub repository.

Let’s begin.

What Is a Dictionary?

Dictionary<TKey,TValue> represents a generic collection of keys and values. It resides in the Systems.Collections.Generic namespace.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

Let’s create an Order class first, and add two simple properties OrderId and Quantity:

public class Order
{
    public Guid OrderId { get; set; }
    public decimal Quantity { get; set; }
}

Now, let’s use the Order class to create a dictionary with an integer key and Order value and populate it with test data:

var ordersDictionary = new Dictionary<int, Order>();

ordersDictionary.Add(1, new Order
{
    OrderId = Guid.NewGuid(),
    Quantity = 25
});
ordersDictionary.Add(2, new Order
{
    OrderId = Guid.NewGuid(),
    Quantity = 35
});
ordersDictionary.Add(3, new Order
{
    OrderId = Guid.NewGuid(),
    Quantity = 45
});

We can not deviate from the type of Dictionary declared, i.e. we will get a compilation error if we add a string key instead of an integer key in the ordersDictionary. The same goes for the type of value as well, we can only add instances of Order object.

Let’s loop through the Dictionary:

foreach (KeyValuePair<int, Order> order in ordersDictionary)
{
    Console.WriteLine($"Key: {order.Key}, Order Id: {order.Value.OrderId}, Quantity: {order.Value.Quantity}");
}

And inspect the result in the console:

Key: 1, Order Id: 768819fb-f589-4eae-b571-0fb0d18b6b67, Quantity: 25 
Key: 2, Order Id: 81f111cb-8b65-4f7d-8e63-e42dab8b0454, Quantity: 35 
Key: 3, Order Id: d333487e-3d35-4659-9599-5b4763564e14, Quantity: 45

A very important fact to know is that Dictionary implements a Hashtable internally.

A detailed article on Dictionary is also available on the website, please go through it to learn more about it.

What Is a Hashtable?

Hashtable represents a collection of key/value pairs that are organized based on the hash code of the key. It resides in the Systems.Collections namespace.

Key and Value both are of object types in Hashtable.

Let’s create a Hashtable and populate it with test data:

var hashTable = new Hashtable();

hashTable.Add(1, 1009);
hashTable.Add(2, "Chicago");
hashTable.Add(3, true);
hashTable.Add("Country", "India");

We can add any type of key/value pair to a Hashtable, it will not raise any compilation error.

Let’s loop through the Hashtable :

foreach (DictionaryEntry item in hashTable.Keys)
{
    Console.WriteLine($"Key: {item.Key}, Value: {item.Value}");
}

And inspect the result in the console:

Key: Country, Value: India 
Key: 3, Value: True 
Key: 2, Value: Chicago 
Key: 1, Value: 1009
Please go through the detailed article on the Hashtable to learn more about it.

Dictionary vs Hashtable

Now, we can compare a Dictionary with a Hashtable with respect to certain pointers.

Type Safety

Dictionary is a type-safe collection. We encounter a compilation error if we add a random key or value other than what types are declared in a dictionary.

Hashtables are not type-safe, we can add any type of key or value.

Enumerated Item

The enumerated item in the case of Dictionary is KeyValuePair, whereas it is DictionaryEntry in the case of a Hashtable.

However, Microsoft suggests using KeyValuePair instead of DictionaryEntry.

Boxing/Unboxing

Hashtable uses object type to hold things internally, hence it needs to do boxing/unboxing in the case of value types.

Dictionary does not need to perform boxing/unboxing because it is a type-safe collection.

Behavior in the Case of a Non-existent Key

Dictionary throws the KeyNotFoundException if we create a query with a key that does not exist, whereas a Hashtable throws null.

Let’s see this in action:

var countriesAndCapitals = new Dictionary<string, string>
{
    { "India","New Delhi"},
    { "Australia","Canberra"},
    { "USA","Washington DC"},
    { "UK","London"}
};

var capitalOfFrance = countriesAndCapitals["France"];

Console.WriteLine(capitalOfFrance);

France does not exist as a key in the countriesAndCapitals dictionary, hence the KeyNotFoundException exception gets thrown:

Unhandled exception. 
System.Collections.Generic.KeyNotFoundException: 
The given key 'France' was not present in the dictionary.

The best way to prevent KeyNotFoundException is to use Dictionary.TryGetValue.

Dictionary vs Hashtable Performance

In this section, we will be using BenchmarkDotNet to measure the performance of a Dictionary and Hashtable.

Let’s see it in action:

private const int ONE_HUNDRED_THOUSAND = 100000;

public static Dictionary<int, string> CreateSmallNumbersDictionary()
{
    var dictionary = new Dictionary<int, string>();

    for (var i = 0; i < ONE_HUNDRED_THOUSAND; i++)
    {
        dictionary.Add(i, $"Data{i}");
    }

    return dictionary;
}
   
public static Hashtable CreateSmallNumbersHashTable()
{
    var hashTable = new Hashtable();

    for (var i = 0; i < ONE_HUNDRED_THOUSAND; i++)
    {
        hashTable.Add(i, $"Data{i}");
    }

    return hashTable;
}

We have 2 methods, namely CreateSmallNumbersDictionary and CreateSmallNumbersHashTable that returns Dictionary and Hashtable objects respectively. Both the Dictionary and Hashtable contain one hundred thousand (100,000) elements.

Now, we need to create the actual methods whose performance we would measure and decorate with [Benchmark] attribute:

[MemoryDiagnoser]
public class BenchmarkProcess
{
    [Benchmark]
    public void BenchmarkDictionary()
    {
        Utility.ReadDictionary(Utility.CreateSmallNumbersDictionary());
    }

    [Benchmark]
    public void BenchmarkHashtable()
    {
        Utility.ReadHashTable(Utility.CreateSmallNumbersHashTable());
    }
}

After we run the project in Release mode, we would see the benchmark results in the BenchmarkDotNet.Artifacts folder:

|                   Method |        Mean |     Error |    StdDev |  Allocated |
|------------------------- |------------:|----------:|----------:|-----------:|
|      BenchmarkDictionary |    16.67 ms |  0.329 ms |  0.338 ms |   11.88 MB |
|       BenchmarkHashtable |    23.42 ms |  0.417 ms |  0.557 ms |    15.3 MB |

For 100,000 elements, the BenchmarkDictionary method takes around 16.67 ms, while the BenchmarkHashTable method takes around 23.42 ms. The dictionary method takes less memory as well. 

Let’s take another test, this time we are going to go with 10,000,000 elements:

|                   Method |        Mean |     Error |    StdDev |  Allocated |
|------------------------- |------------:|----------:|----------:|-----------:|
| BenchmarkLargeDictionary | 2,043.07 ms | 36.277 ms | 32.159 ms | 1086.83 MB |
|  BenchmarkLargeHashtable | 3,113.23 ms | 60.324 ms | 56.427 ms | 2003.88 MB |

For even a relatively larger input, Dictionary performs better than Hashtable. The mean time taken by Dictionary is around 2.04 seconds in comparison to the 3.11 seconds taken by Hashtable.

The Dictionary method consumes around 1087 MBs of memory as compared to the 2004 MBs of memory consumed by the Hashtable method. A performance betterment of around 45%.

Results Summary

Going by the test numbers, we can safely say that a Dictionary performs better as compared to a Hashtable for larger inputs. The performance will be actually comparable if we take into account smaller inputs.

We should choose Dictionary over Hashtable wherever required because Dictionary is a generic collection and provides type safety. It does not go through the unnecessary process of boxing/unboxing in the case of value types.

Conclusion

In this article, we have learned about two of the common collections in C# – Dictionary and Hashtable, and we’ve seen what the differences between them are. We’ve also learned that in some cases we should prefer a Dictionary over a Hashtable.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!