If you have ever written anything in Python, I am sure you have stumbled across the immensly useful “SetDefault” method. Chances are if you came here via search, you know what this means, jump to the implementation – if not, read on.
Background
Basically, SetDefault checks to see if a key exists in a dictionary – if so, it returns the value associate with it. If not, it creates the value, inserts it into the dictionary, and then returns the value. A typical usage would be when you want to cache something – instead of this:
var d = new Dictionary<string, string>();
if (d.ContainsKey("somecachekey"))
{
return d["somecachekey"];
}
else
{
string result = SomeMethodToGenerateValue("somecachekey", someOtherStuff);
d.Add("somecachekey", result);
return result;
}
SetDefault would allow you to just write:
var d = new Dictionary<string, string>();
d.SetDefault("somecachekey", () => SomeMethodToGenerateValue("somecachekey", someOtherStuff));
The benefit here is rather marginal. However, where this comes into it’s own is when you have Dictionary of Dictionaries, or a Dictionary of Lists. This happens all the time when dealing with trees and tree like structures. Here, your code to add a new node simply becomes:
var children = new Dictionary<string, List<Node>>();
d.SetDefault("left", () => new List<Node>()).Add(childNode);
This code would check to see if there was already a list associated with the key “left” in your collection. If so, it would add the childNode to it; otherwise, it would create a new list and then add the child node to that list.
Even better, .Net allows you create a default instance of a object with Activator.CreateInstance() so you can make things even more succinct with a SetDefault(key) method that will instantiate and return the default instance of TValue if the key doesn’t exist:
var children = new Dictionary<string, List<Node>>();
d.SetDefault(“left”).Add(childNode);
Implementation
Here’s the simple version of the code – you can find the complete source here (including the default instance version): SetDefaultExtension.cs:
public static class SetDefaultExtension
{
public static TValue SetDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TValue> initFunction)
{
TValue result;
if (!dictionary.TryGetValue(key, out result))
return dictionary[key] = initFunction();
return result;
}
}
Now, if you use the namespace you’ve given the class all objects that implement IDictionary<TKey, TValue> will now support the .SetDefault method.
For what it’s worth, SetDefault is a weird name, but I’ll stick with conventions.