Dictionary vs Hashtable in C#: Why Dictionary Always Wins

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Dictionary vs Hashtable: The Battle of Collections in C#

\n\n

Imagine this situation: you are writing code in C#, and you need to quickly store and retrieve data by key. You open the documentation and see two similar classes — Dictionary and Hashtable. Both work on the "key-value" principle, both promise lightning-fast data access. But which one to choose?

\n\n

If you've asked yourself this question, you are not alone. On Stack Overflow, the topic "Why is Dictionary preferred over Hashtable in C#?" has gathered thousands of views and hundreds of votes. And today we will settle this question once and for all. Spoiler: Dictionary almost always wins. But let's break down why.

\n\n

A Brief History Lesson: Where Did Hashtable Come From?

\n\n

To understand the essence of this rivalry, we need to look into the history of C#. When the .NET platform first appeared (version 1.0), developers had access to the Hashtable class from the System.Collections namespace. It was a classic hash table that could store any objects. Sounds cool, right? But there was one problem — lack of typing.

\n\n

With the release of .NET 2.0 and the introduction of generics, Microsoft introduced a new collection — Dictionary<TKey, TValue> from the System.Collections.Generic namespace. And that's when the real magic began.

\n\n

Type Safety: The Main Advantage of Dictionary

\n\n

Let's look at a specific code example. Here's how working with Hashtable looks:

\n\n
// Old way: Hashtable\nHashtable hashtable = new Hashtable();\nhashtable.Add("key1", 123);\nhashtable.Add("key2", "string"); // Error? No, it will compile!\nhashtable.Add(456, "another string"); // The key can also be any object\n\n// Now let's try to retrieve the data\nint value = (int)hashtable["key2"]; // Oops! InvalidCastException at runtime!
\n\n

See the problem? Hashtable accepts any types — for both keys and values. The compiler will let any error through, and you'll only find out about it during program execution. This is a direct path to bugs that are hard to catch.

\n\n

Now let's look at Dictionary:

\n\n
// New, correct way: Dictionary\nDictionary<string, int> dictionary = new Dictionary<string, int>();\ndictionary.Add("key1", 123);\n// dictionary.Add("key2", "string"); // Compilation error! Type mismatch\n// dictionary.Add(456, "another string"); // Also an error — key must be string\n\n// Retrieve data without casting\nint value = dictionary["key1"]; // Clean, safe, elegant
\n\n

Dictionary is type-safe. You explicitly specify what types the keys and values will be. The compiler checks this at build time. No unexpected runtime exceptions — the code either works or doesn't compile.

\n\n

Performance: Which is Faster?

\n\n

The second important aspect is performance. And here, Dictionary pulls ahead again. Why? It's all about boxing and unboxing.

\n\n

When you work with Hashtable, all value types (int, double, struct, etc.) are boxed into objects. This creates overhead for the garbage collector and slows down execution. Let's test this in practice:

\n\n
// Hashtable: boxing/unboxing\nHashtable ht = new Hashtable();\nStopwatch sw = Stopwatch.StartNew();\nfor (int i = 0; i < 1000000; i++)\n{\n    ht.Add(i, i); // Each int is boxed into object\n}\nsw.Stop();\nConsole.WriteLine($"Hashtable adding: {sw.ElapsedMilliseconds} ms");\n\n// Dictionary: no boxing\nDictionary<int, int> dict = new Dictionary<int, int>();\nsw.Restart();\nfor (int i = 0; i < 1000000; i++)\n{\n    dict.Add(i, i); // No boxing — working with int directly\n}\nsw.Stop();\nConsole.WriteLine($"Dictionary adding: {sw.                

Blogs

Book Recommendations