I'm very much enjoying David Fowler's tweets, and since he doesn't have a blog, I will continue to share and expand on his wisdom so that it might reach a larger audience.
He had a conversation with Stephen Toub where Stephen points out that “.NET has 4 built-in dictionary/map types [and] there’s no guidance on when to use what, mostly individual documentation on each implementation.”
There is actually some good documentation on C# Collections and Data Structures here that we can compare and combine with Stephen Toub's good advice (via David) as well!
There are two main types of collections; generic collections and non-generic collections. Generic collections are type-safe at compile time. Because of this, generic collections typically offer better performance.
Definitely important to remember. Generics have been around since .NET Framework 2.0 around 15 years ago so this is a good reason to consider avoiding Hashtable and using Dictionary<> instead. Hashtable is weakly typed and while it allows you to have keys that map to different kinds of objects which may seem attractive at first, you'll need to “box” the objects up and boxing and unboxing is expensive. You'll almost always want to use Dictionary instead.
If you're accessing your collection across threads, consider the System.Collections.Concurrent namespace or using System.Collections.Immutable which is thread-safe because you'll always be working on a copy as the original collection is immutable (not modifiable).
David says this about
- ConcurrentDictionary – “Good read speed even in the face of concurrency, but it’s a heavyweight object to create and slower to update.”
- Dictionary with lock – “Poor read speed, lightweight to create and medium update speed.”
- Dictionary as immutable object – “best read speed and lightweight to create but heavy update. Copy and modify on mutation e.g. new Dictionary(old).Add(key, value)”
- Hashtable – “Good read speed (no lock required), same-ish weight as dictionary but more expensive to mutate and no generics!”
- ImmutableDictionary – “Poorish read speed, no locking required but more allocations require to update than a dictionary.”
Another one that isn't often used but I'll add as it's good to know about is
- KeyedCollection – Generic and ordered. Uses Dictionary and List underneath
This is great advice from David:
Use the most obvious one until it bites you. Most software engineering is like this.
Measure and test, measure and test. Good luck to you!
Sponsor: Make login Auth0’s problem. Not yours. Provide the convenient login features your customers want, like social login, multi-factor authentication, single sign-on, passwordless, and more. Get started for free.