SetDefault for C# Dictionary / IDictionary

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.

Post a comment or leave a trackback: Trackback URL.

Leave a comment