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.