This post’s about a simple extension to the Dictionary<TKey, TValue> type in .NET. It won’t change the world, but it’s a nice tool to have in the shed. I’ve quite possibly reinvented the wheel, here, too – if there’s something already floating around in the BCL that I’ve missed, please let me know :-).
What does it do?
The extension simplifies working with Dictionaries that contain zero, one or many Values corresponding to each potential TKey.
How does it do it?
The naive (and simplest!) approach is to declare a Dictionary<TKey, List<TValue>>, and do the plumbing manually when adding a new value for a key. That is, when you’re adding a new value V for a key K, you need to detect the case where there is no List<TValue> for that K, and construct a List<TValue> and add it to the Dictionary so you can then add the V to the end of your List<TValue>.
Well, I’ve written that code three times over the last six months, so I’ve made a generic extension to Dictionary<TKey, TValue> which does the above.
[code:c#]
public class MultiValueDictionary<TKey, TValue> :
Dictionary<TKey, List<TValue>>
{
public
MultiValueDictionary()
{
}
public void Add(TKey key, TValue value)
{
List<TValue> valueList;
if (base.TryGetValue(key, out valueList))
{
valueList.Add(value);
}
else
{
base.Add(key, new List<TValue>()
{ value });
}
}
Why bother?
For a recent project, I had a whole buncha legacy code parsed into a Abstract Syntax Trees. I wanted to traverse the trees just once each (to improve locality of reference), applying transformations from a large-ish library based on the type of the current node. So a Dictionary<NodeType, ITransformer> gives me some of what I need, but falls down when I want to have multiple ITransformers for a single NodeType.
So, instead of using a Dictionary<NodeType, ITransformer>, I use a MultValueDictionary<NodeType, ITransformer>, which provides all the functionality of Dictionary<NodeType, List<ITransformer>> as well as a convenient Add() overload which takes care of constructing a new List in the (most common) case where there’s no existing List for that value of NodeType.