Search code examples
c#collectionsdictionary

Is there a more elegant way of adding an item to a Dictionary<> safely?


I need to add key/object pairs to a dictionary, but I of course need to first check if the key already exists otherwise I get a "key already exists in dictionary" error. The code below solves this but is clunky.

What is a more elegant way of doing this without making a string helper method like this?

using System;
using System.Collections.Generic;

namespace TestDictStringObject
{
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<string, object> currentViews = new Dictionary<string, object>();

            StringHelpers.SafeDictionaryAdd(currentViews, "Customers", "view1");
            StringHelpers.SafeDictionaryAdd(currentViews, "Customers", "view2");
            StringHelpers.SafeDictionaryAdd(currentViews, "Employees", "view1");
            StringHelpers.SafeDictionaryAdd(currentViews, "Reports", "view1");

            foreach (KeyValuePair<string, object> pair in currentViews)
            {
                Console.WriteLine("{0} {1}", pair.Key, pair.Value);
            }
            Console.ReadLine();
        }
    }

    public static class StringHelpers
    {
        public static void SafeDictionaryAdd(Dictionary<string, object> dict, string key, object view)
        {
            if (!dict.ContainsKey(key))
            {
                dict.Add(key, view);
            }
            else
            {
                dict[key] = view;
            }
        }
    }
}

Solution

  • Just use the indexer - it will overwrite if it's already there, but it doesn't have to be there first:

    Dictionary<string, object> currentViews = new Dictionary<string, object>();
    currentViews["Customers"] = "view1";
    currentViews["Customers"] = "view2";
    currentViews["Employees"] = "view1";
    currentViews["Reports"] = "view1";
    

    Basically use Add if the existence of the key indicates a bug (so you want it to throw) and the indexer otherwise. (It's a bit like the difference between casting and using as for reference conversions.)

    If you're using C# 3 and you have a distinct set of keys, you can make this even neater:

    var currentViews = new Dictionary<string, object>()
    {
        { "Customers", "view2" },
        { "Employees", "view1" },
        { "Reports", "view1" },
    };
    

    That won't work in your case though, as collection initializers always use Add which will throw on the second Customers entry.