James Manning's Blog

February 22, 2010

another extension method: GetValueOrDefault for Dictionary

Filed under: Uncategorized — manningj @ 4:58 am

as many of you remember, Hashtable did (well, still does) store objects (just like ArrayList and the other non-generic collections).  When a key wasn’t found, it would return null back as a way of saying “not found”.  This was kind of painful as an approach, since many times applications ended up with null refs after doing a failed lookup that didn’t throw.

Dictionary fixed that such that lookup that fails to find the key will throw since, being generic, the value type (as in, the TValue type in the generic type params) might be, well, a value type (as in, not a reference type, so it can’t be null), so you can’t use null for differentiating failed-lookup from look-succeeded-and-found-value-of-null).  If you want to try and get the value but not have an exception to deal with if it’s not there, Dictionary gives you TryGetValue which will try to fetch the value (into an out variable you have to declare first) and then return a bool for whether or not the lookup succeeded.  It gives you everything you need.

If you hate that change in behavior, don’t worry, it was hashed out (internally and externally) to death – here’s a related blog post about the change from during the Whidbey cycle – the comments should give you an idea of the sides involved.

The really annoying thing, though, is the resulting verbosity of code that wants to use a Dictionary (for type safety, to avoid casts, etc).  You’ll often end up with something like:

string mimeType;
if (MimeMap.TryGetValue(extension, out mimeType))
{
    return mimeType;
}
else
{
    return "binary/octet-stream";
}

Kind of annoying, hunh?  It’s a lot of text and control flow for the relatively simple concept of “return the value for a successful lookup, return this default otherwise.”

So, extension methods to the rescue, of course. :)

Since the above pattern will be the same for all such scenarios, we can genericize it for Dictionary:

public static TValue GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> self, TKey key, TValue defaultValue)
{
    TValue val;
    if (self.TryGetValue(key, out val))
    {
        return val;
    }
    else
    {
        return defaultValue;
    }
}

The 2 generic type params might seem scary, but since they’re the same ones in the dictionary that’s passed in, the compiler can infer them, so you won’t have to specify them yourself.

Now the original snippet of code reduces to the easier-to-read-and-understand:

return MimeMap.GetValueOrDefault(extension, "binary/octet-stream");

I’m sure this will cause twitching in some readers, but I like it :)


Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.