Hello there
My current technology stack: .NET 9, Python, TypeScript, and Azure.
I develop microservices and terraform of different sizes. Sharing my challenges and key learning.
About
The views expressed in this blog are my own and do not reflect my employer's. I am not responsible for any consequences of using the information provided. This blog is for educational purposes only, not for commercial use. Readers should apply their own judgment.
Collection Performance in .NET 9
.NET 9 Performance Comparison: Hashtable vs Dictionary vs List vs Collection
.NET 9 includes several performance improvements, particularly in collections like Hashtable, Dictionary, List, and HashSet. This post compares their performance and suitability for different use cases.
Dictionary<TKey, TValue> vs Hashtable
Dictionary<TKey, TValue>is a generic collection that provides O(1) average-time complexity for lookups.Hashtableis a non-generic collection, requiring boxing/unboxing for value types, making it less efficient.
List
List<T>is an ordered collection with fast index-based access but slower search times compared to hash-based structures.
Other Collections
ArrayListis a non-generic collection that stores objects and suffers from boxing/unboxing overhead.HashSet<T>provides unique elements with fast lookups, making it useful for membership tests.
Benchmark Code
public class CollectionPerformance
{
private Dictionary<int, int> dictionary;
private Hashtable hashtable;
private List<int> list;
private HashSet<int> hashSet;
private int searchKey = 999999;
public void Setup()
{
dictionary = new Dictionary<int, int>();
hashtable = new Hashtable();
list = new List<int>();
hashSet = new HashSet<int>();
for (int i = 0; i < 1000000; i++)
{
dictionary[i] = i;
hashtable[i] = i;
list.Add(i);
hashSet.Add(i);
}
}
public void DictionaryLookup() => dictionary.ContainsKey(searchKey);
public void HashtableLookup() => hashtable.ContainsKey(searchKey);
public void ListLookup() => list.Contains(searchKey);
public void HashSetLookup() => hashSet.Contains(searchKey);
}
Test Environment
- Processor: 13th Gen Intel Core i7-1370P, 1 CPU, 20 logical and 14 physical cores
- .NET SDK: 9.0.103
- Runtime: .NET 9.0.2 (9.0.225.6610), X64 RyuJIT AVX2
Benchmark Results
| Method | Mean | Error | StdDev | Median | P95 | Gen0 | Allocated |
|---|---|---|---|---|---|---|---|
| DictionaryLookup | 1.806 ns | 0.1874 ns | 0.4936 ns | 1.660 ns | 3.375 ns | - | - |
| HashtableLookup | 9.726 ns | 0.3621 ns | 1.0620 ns | 9.591 ns | 11.761 ns | 0.0019 | 24 B |
| ListLookup | 112,984.793 ns | 2,973.6506 ns | 8,483.9931 ns | 115,142.621 ns | 123,135.237 ns | - | - |
| HashSetLookup | 3.272 ns | 0.1454 ns | 0.4218 ns | 3.317 ns | 3.922 ns | - | - |
Analysis & Key Takeaways
- Dictionary<TKey, TValue> offers the best balance of speed and memory efficiency for key-based lookups.
- Hashtable is significantly slower due to boxing/unboxing overhead and additional memory allocation.
- List
performs poorly in large datasets as it relies on O(n) linear search, making it unsuitable for frequent lookups. - HashSet
is one of the fastest structures for lookups and ideal when uniqueness is required.
Conclusion
For most key-value lookups:
- Use Dictionary<TKey, TValue> for the best trade-off between speed and memory.
- Avoid Hashtable unless legacy support is required.
- Use List
only when preserving order is necessary. - Prefer HashSet
when unique items and fast lookups are needed.