The first pattern I often encounter, is checking whether or not a key exists in the dictionary before attempting to retrieve the value. As we know, the dictionary throws an exception if the key does not exist. Yes, I know there is TryGetValue-method, but then you have to meddle with out-parameters and your get-code is already more than one line. The extension method GetOrDefault below aims at solving this. Instead of throwing an exception when the key is not present, it returns the default value of that class.
The second pattern I often use is also related to non-existent keys. But this time I want to construct a new object if it doesn't exist, and work with this new object in the code lines to come. There is an elegant solution to this as well using generics, although it will require the value type to be of a class type. See method GetOrInsertNew below on how I solved that in four lines.
Here is the complete class:
public static class DictionaryExtensions
{
/// <summary>
/// Returns the default value of type U if the key does not exist in the dictionary
/// </summary>
public static U GetOrDefault<T, U>(this Dictionary<T, U> dic, T key)
{
if (dic.ContainsKey(key)) return dic[key];
return default(U);
}
/// <summary>
/// Returns an existing value U for key T, or creates a new instance of type U using the default constructor,
/// adds it to the dictionary and returns it.
/// </summary>
public static U GetOrInsertNew<T, U>(this Dictionary<T, U> dic, T key)
where U : new()
{
if (dic.ContainsKey(key)) return dic[key];
U newObj = new U();
dic[key] = newObj;
return newObj;
}
}
As an example of how using this improves the readability of your code, let's say you're building some kind of custom session handling for some sort of service. Using plain Dictionary without the extension, you could implement the GetSession-method like this:
private Dictionary<string, Session> _sessionDic;
public Session GetSession(string sessionId)
{
if (_sessionDic.ContainsKey(sessionId)) return _sessionDic[sessionId];
var session = new Session();
_sessionDic[sessionId] = session;
return session;
}
Now using the extension methods, the retrieving code could be reduced to one line:
private Dictionary<string, Session> _sessionDic;
public Session GetSession(string sessionId)
{
return _sessionDic.GetOrInsertNew(sessionId);
}
Another convenience is that if you are like me and work with other languages that are dynamically typed, like Javascript or PHP, the Dictionary will now behave more like their counterparts Associative arrays in Javascript and Arrays in PHP. (Yes I know they're far from exactly the same, but they have comparable behaviour)
In summary, this is no sorcery - just a simple tool that I have found to be nice to have in my toolbox, and what I believe to be a good application of extension methods.
Update 11th Feb 2013:
Simen's suggestion from the comments is implemented and posted to this public github gist

Nice extensions, but I think you can improve them a bit: GetOrDefault should be able to take a custom default value, and TryGetValue should be used.
ReplyDeleteI think TryGetValue will be faster in release mode as only *one* lookup is performed instead of two as in ContainsKey + getvalue (but I might be wrong).
public static V GetOrDefault(this Dictionary dict, K key, V onMissing = default(V))
{
V value;
return dict.TryGetValue(key, out value) ? value : onMissing;
}
Pre tag not allowed and < and > wasn't rendered correcly. Here it is again:
Deletepublic static V GetOrDefault<K, V>(this Dictionary<K, V> dict, K key, V onMissing = default(V))
{
V value;
return dict.TryGetValue(key, out value) ? value : onMissing;
}
Thank's Simen that is definitely an improvement! Have posted the updated code to github and linked to it from the bottom of the post.
ReplyDelete