C# Dictionary Best Practices And What To Avoid

Dictionary Best Practices And What To Avoid Page Banner Image

Introduction

Dictionary using best practices with the right key scales well over large datasets. Several pitfalls should be avoided. In C#, the dictionary is one of my favorite go-to data structures when I need top performance from my app. I also learned this long ago and was one the consistant issues that I ran into until I started programming more defensively. I have also seen other developers make simliar mistakes by not using theses practices and erros occured.

Video Code Walkthrough

Dictionary Add Key-Value Pairs

Add Function

To add new key value pairs we use the Add function from a dictionary object. It takes a key and value of any type. Values can be duplicated, but keys must be unique.

static void Main(string[] args)
{
    Dictionary<string, string> lockerNumberContendsDictionary = new Dictionary<string, string>();
    lockerNumberContendsDictionary.Add("5849", "backpack");
    lockerNumberContendsDictionary.Add("3425", "lunch bag");
    lockerNumberContendsDictionary.Add("434", "cell phone");
    lockerNumberContendsDictionary.Add("2", "basketball");
    foreach (string lockerNumber in lockerNumberContendsDictionary.Keys)
    {
        string contends = lockerNumberContendsDictionary[lockerNumber];
        Console.WriteLine($"Locker#:{lockerNumber}, Contends:{contends}");
    }
}
Code Output
Locker#:5849, Contends:backpack
Locker#:3425, Contends:lunch bag
Locker#:434, Contends:cell phone
Locker#:2, Contends:basketball

Another way to add key value pairs and my preferred way but either way works. This used the setter for the dictionary', by setting the value to the key it is also adding the key to the dictionary.

static void Main(string[] args)
{
    Dictionary<string, string> lockerNumberContendsDictionary = new Dictionary<string, string>();
    lockerNumberContendsDictionary["5849"] = "backpack";
    lockerNumberContendsDictionary["3425"] = "lunch bag";
    lockerNumberContendsDictionary["434"] = "cell phone";
    lockerNumberContendsDictionary["2"] = "basketball";
    Console.WriteLine($"Locker#:5849, Contends:{lockerNumberContendsDictionary["5849"]}");
    Console.WriteLine($"Locker#:3425, Contends:{lockerNumberContendsDictionary["3425"]}");
    Console.WriteLine($"Locker#:434, Contends:{lockerNumberContendsDictionary["434"]}");
    Console.WriteLine($"Locker#:2, Contends:{lockerNumberContendsDictionary["2"]}");
}
Code Output
Locker#:5849, Contends:backpack
Locker#:3425, Contends:lunch bag
Locker#:434, Contends:cell phone
Locker#:2, Contends:basketball

Add Errors

System.ArgumentException:An item with the same key has already been added

The following lines of code try to add 6 key-value pairs to the dictionary but the last two keys are duplicated and thus an exemption is thrown on line 8. To avoid this kind of exception we need to check the dictionary if the key exists already. Always check if the key exists in the dictionary before trying to add a new key-value pair.

static void Main(string[] args)
{
    Dictionary<string, string> lockerNumberContendsDictionary = new Dictionary<string, string>();
    lockerNumberContendsDictionary.Add("5849", "backpack");
    lockerNumberContendsDictionary.Add("3425", "lunch bag");
    lockerNumberContendsDictionary.Add("434", "cell phone");
    lockerNumberContendsDictionary.Add("2", "basketball");
    lockerNumberContendsDictionary.Add("3425", "tennis racket");
    lockerNumberContendsDictionary.Add("5849", "pillow");
}

Check if Key Exists Already

ContainsKey Method Chart

Before adding any key value combination to the dictionary check to see if the key already exists. Examine the code snippet below. There can not be two keys in the dictionary. Use the ContainsKey function to find if the key already exists in the dictionary.

Check if Key Exists Video

Check if Key Exists Code

TryGetValue Method Syntax Image
public static bool CheckIfKeyExists(string key, string value, Dictionary<string, string> dictionary)
{
    if (!dictionary.ContainsKey(key))
    {
        dictionary.Add(key, value);
        return true;
    }
    else
    {
        return false;
    }
}
Use TryAdd To Simply The Code
TryAdd Method Chart

You can also use the TryAdd method to simply this. It checks if the key exists and adds if necessary. It doesn't throw an error. Let's see how it looks below.

TryAdd Video Example
TryAdd Code Example
TryGetValue Method Syntax Image
public static bool CheckIfKeyExists(string key, string value, Dictionary<string, string> dictionary)
{
    if (dictionary.TryAdd(key, value))
    {
        return true;
    }
    else
    {
        return false;
    }
}

Next, we add items to this dictionary. Let’s assume that we have a set of locker numbers that can only hold one item each. We will attempt to add 6 items but if a locker number already exists in our dictionary then that item will not be added.

static void Main(string[] args)
{
    Dictionary<string, string> lockerNumberContendsDictionary = new Dictionary<string, string>();
    CheckIfKeyExists("5849", "backpack", ref lockerNumberContendsDictionary);
    CheckIfKeyExists("3425", "lunch bag", ref lockerNumberContendsDictionary);
    CheckIfKeyExists("434", "cell phone", ref lockerNumberContendsDictionary);
    CheckIfKeyExists("2", "basketball", ref lockerNumberContendsDictionary);
    CheckIfKeyExists("3425", "tennis racket", ref lockerNumberContendsDictionary);
    CheckIfKeyExists("5849", "pillow", ref lockerNumberContendsDictionary);
    foreach (string lockerNumber in lockerNumberContendsDictionary.Keys)
    {
        string contends = lockerNumberContendsDictionary[lockerNumber];
        Console.WriteLine($"Locker#:{lockerNumber}, Contends:{contends}");
    }
}

As we can see that unique keys can be added to the dictionary. The items tennis racket and pillow could not be added because those keys already exist.

Additional Information On ContainsKey and TryAdd

I've written another article comparing TryAdd and ContainsKey in performance so see Check If The Key Exists In The C# Dictionary

Get Value

Accessing the dictionary is done by passing the key value in the brackets ‘[]’, which is called the indexer. The value is returned almost instantly without any search done. This speed is the main strength of the dictionary, this quick access to the values. You can see the syntax of the get value in lines 9-12 below.

static void Main(string[] args)
{
    Dictionary<string, string> lockerNumberContendsDictionary = new Dictionary<string, string>();
    lockerNumberContendsDictionary.Add("5849", "backpack");
    lockerNumberContendsDictionary.Add("3425", "lunch bag");
    lockerNumberContendsDictionary.Add("434", "cell phone");
    lockerNumberContendsDictionary.Add("2", "basketball");
    Console.WriteLine($"Locker#:5849, Contends:{lockerNumberContendsDictionary["5849"]}");
    Console.WriteLine($"Locker#:3425, Contends:{lockerNumberContendsDictionary["3425"]}");
    Console.WriteLine($"Locker#:434, Contends:{lockerNumberContendsDictionary["434"]}");
    Console.WriteLine($"Locker#:2, Contends:{lockerNumberContendsDictionary["2"]}");
}

Get Value Errors

System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary

This exemption comes when we try to get a value from a key that does not currently exists in the dictionary. See the example below, when the key “244324” was not added to the dictionary and then was it accessed.

static void Main(string[] args)
{
    Dictionary<string, string> lockerNumberContendsDictionary = new Dictionary<string, string>();
    lockerNumberContendsDictionary.Add("5849", "backpack"); lockerNumberContendsDictionary.Add("3425", "lunch bag");
    lockerNumberContendsDictionary.Add("434", "cell phone");
    lockerNumberContendsDictionary.Add("2", "basketball");
    Console.WriteLine($"Locker#:5849, Contends:{lockerNumberContendsDictionary["5849"]}");
    Console.WriteLine($"Locker#:3425, Contends:{lockerNumberContendsDictionary["3425"]}");
    Console.WriteLine($"Locker#:434, Contends:{lockerNumberContendsDictionary["434"]}");
    Console.WriteLine($"Locker#:2, Contends:{lockerNumberContendsDictionary["2"]}");
    Console.WriteLine($"Locker#:2444324, Contends:{lockerNumberContendsDictionary["2444324"]}");
}

Protect Get Code By ContainsKey

There are two ways to guard against this exception. The first is the check to see if the key exists in the dictionary before trying to access that key.

Protect Get Code By ContainsKey Video Example

Protect Get Code By ContainsKey Code Example

TryGetValue Method Syntax Image
public static string GetValueByCheckIfKeyExists(string key, ref Dictionary<string, string> dictionary)
{
    if (dictionary.ContainsKey(key))
    {
        return dictionary[key];
    }
    else
    {
        return "";
    }
}

Protect Get Code By TryGetValue

TryGetValue Method Chart

The second safe way to get the value of a key is to use the TryGetValue function. I prefer this way too for two reasons. It checks if the key exists and returns true and the out parameter returns the value. This is slightly faster than checking for the key first and then getting the value in the previous method.

Protect Get Code By TryGetValue Video Example

Protect Get Code By TryGetValue Code Example

TryGetValue Method Syntax Image
public static string GetValueByTryGetValue(string key, ref Dictionary<string, string> dictionary)
{
    string value = "";
    if (dictionary.TryGetValue(key, out value))
    {
        return value;
    }
    else
    {
        return "";
    }
}

The below example uses both protections against this exception. Both return the value when the key exists and both return an empty string when the key doesn’t exist in the dictionary. This would conclude the dictionary best practices of this collection type.

static void Main(string[] args)
{
    Dictionary<string, string> lockerNumberContendsDictionary = new Dictionary<string, string>();
    lockerNumberContendsDictionary.Add("5849", "backpack");
    lockerNumberContendsDictionary.Add("3425", "lunch bag");
    lockerNumberContendsDictionary.Add("434", "cell phone");
    lockerNumberContendsDictionary.Add("2", "basketball");
    Console.WriteLine($"GetValueByCheckIfKeyExists - Locker#:5849, Contends:{GetValueByCheckIfKeyExists("5849", ref lockerNumberContendsDictionary)}");
    Console.WriteLine($"GetValueByTryGetValue - Locker#:3425, Contends:{GetValueByTryGetValue("3425", ref lockerNumberContendsDictionary)}");
    Console.WriteLine($"GetValueByCheckIfKeyExists - Locker#:434, Contends:{GetValueByCheckIfKeyExists("434", ref lockerNumberContendsDictionary)}");
    Console.WriteLine($"GetValueByTryGetValue - Locker#:2, Contends:{GetValueByTryGetValue("2", ref lockerNumberContendsDictionary)}");
    Console.WriteLine($"GetValueByCheckIfKeyExists - Locker#:2444324, Contends:{GetValueByCheckIfKeyExists("2444324", ref lockerNumberContendsDictionary)}");
    Console.WriteLine($"GetValueByTryGetValue - Locker#:32354, Contends:{GetValueByTryGetValue("32354", ref lockerNumberContendsDictionary)}");
}
Code Output
GetValueByCheckIfKeyExists - Locker#:5849, Contends:backpack
GetValueByTryGetValue - Locker#:3425, Contends:lunch bag
GetValueByCheckIfKeyExists - Locker#:434, Contends:cell phone
GetValueByTryGetValue - Locker#:2, Contends:basketball
GetValueByCheckIfKeyExists - Locker#:2444324, Contends:
GetValueByTryGetValue - Locker#:32354, Contends:
Additional Information On ContainsKey and TryGetValue

I've written another article comparing TryGetValue and ContainsKey in performance so see TryGetValue Vs ContainsKey With Indexer In .NET

Conclusion

For adding you should use TryAdd because it does two things at once by checking the if they doesn't exist and then add.

For getting the value, you should use TryGetValue because it checks if it is safe to get the value from that key.

You should be using these methods in some form or another because other wise you'll be open to errors from invalid inputs duplicated inputs. There will ensure that the inputs will be checked and create a better

Get Latest Updates