In this article, we are going to present you solutions on how to return a default value from a Dictionary in C# and run an evaluation test against these methods to find the most efficient.

To download the source code for this article, you can visit our GitHub repository.

Let’s begin.

When Do We Need to Return a Default Value From a Dictionary

One of the most common Dictionary collections, we utilize in .NET is the Dictionary<TKey, TValue> class, where TKey is the type of keys and TValue is the type of value. An issue that arises frequently is when we try to retrieve an element using a key that does not exist. The program throws a KeyNotFoundException as expected.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

In this article, we will handle the non-existing keys by returning the default value type of the elements.

Using the ContainsKey() Method

First, let’s make use of the common ContainsKey method:

var myDictionary = new Dictionary<string, int>
{
    { "alice", 1 },
    { "bob", 2 },
    { "mike", 3 }
};

var searchKey = "tom";

Console.WriteLine(myDictionary.ContainsKey(searchKey) ? myDictionary[searchKey] : default);

We construct the simple  dictionary myDictionary instance with a string type for the keys and an int type for the values. We assign to the searchKey variable a key that is not present in our collection. With the use of the null coalescing ? operator, we check if this key exists in the dictionary. If it does, we return the value. Οtherwise, we return the default value, which in our case is the zero value.

Using the TryGetValue() Method

Another approach is the TryGetValue method. It is a built-in method of the Dictionary<TKey, TValue> class in C#, which takes two parameters. The first is the key to look for in the dictionary. The second is an out parameter to store the value associated with the key. It returns a Boolean value, that indicates whether the key exists in the collection.

So, let’s perform the same example with the use of the TryGetValue method:

Console.WriteLine(myDictionary.TryGetValue(searchKey, out var result) ? result : default);

Here, if the key exists in our dictionary, we return the out result variable, otherwise, we return the default type of values in our collection. 

According to the CA1854 performance rule, we should prefer the TryGetValue method over the ContainsKey method, when we want to retrieve the associated value of the key too. That is because the myDictionary[searchKey] Dictionary indexer access in TryGetValue extension is already guarded by the ContainsKey  check. That said, in the first example, our code will perform a double look-up in the dictionary, while with the TryGetValue method it will search in the collection only once.

Using the GetValueOrDefault() Method to Return a Default Value from a Dictionary

In C# 7.1, Microsoft introduces the GetValueOrDefault<TKey, TValue>() method, a collection extension, which is exactly what we are looking for. When the method is successful, it returns the value associated with the specified key. When it fails, it returns the defaultValue.

Let’s use it in our example:

Console.WriteLine(myDictionary.GetValueOrDefault(searchKey));

We simply call the extension with a searchKey value as the single argument. 

Let’s take a deeper look at the source code of the GetValueOrDefault extension:

TValue GetValueOrDefault(TKey key) {
    int i = FindEntry(key);
    if (i >= 0) {
        return entries[i].value;
    }
    return default(TValue);
}

In contrast to the TryGetValue method, the compiled code here omits the step of assigning the value to the out variable as it returns it directly.

Performance Benchmarks

We will evaluate these methods to find the most efficient one in terms of speed, with the benchmark class:

[MemoryDiagnoser]
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
[RankColumn]
public class DefaultValueFromDictionaryInCSharpBenchmark
{
    private Dictionary<string, int> _myDictionary = FillDictionary();

    private readonly string _key = "number_1000";

    [Benchmark]
    public int ContainsKey()
    {
        return _myDictionary.ContainsKey(_key) ? _myDictionary[_key] : default;
    }

    [Benchmark]
    public int TryGetValue()
    {
        return _myDictionary.TryGetValue(_key, out var value) ? value : default;
    }

    [Benchmark]
    public int GetValueOrDefault()
    {
        return _myDictionary.GetValueOrDefault(_key);
    }

    private static Dictionary<string, int> FillDictionary()
    {
        var myDictionary = new Dictionary<string, int>();

        for (int i = 1; i < 10000; i++)
        {
            myDictionary.Add($"number_{i}", i);
        }
        return myDictionary;
    }
}

We create a Dictionary collection with 10000 records. Then, we assign a value to our search key that exists in our implemented collection. Finally, we have three methods to benchmark our suggested solutions accordingly.

Now, let’s take a look at the results:

|            Method |     Mean |    Error |   StdDev | Rank | Allocated |
|------------------ |---------:|---------:|---------:|-----:|----------:|
| GetValueOrDefault | 23.23 ns | 0.245 ns | 0.217 ns |    1 |         - |
|       TryGetValue | 23.44 ns | 0.726 ns | 2.073 ns |    1 |         - |
|       ContainsKey | 49.27 ns | 1.028 ns | 2.028 ns |    2 |         - |

We can see that the GetValueOrDefault method and the TryGetValue method produce nearly the same outcome when it comes to efficiency. The GetValueOrDefault method has a mean time of 23.23 nanoseconds, while the TryGetValue method has a mean time of 23.44 nanoseconds. We also verify that when we use the ContainsKey method, our program needs approximately twice the time to return the value we search for, with a mean time of 49.27 nanoseconds.

Now we will run the same benchmark with a search key that does not exist in our dictionary. We assign to our key the following value:

private readonly string key = "number_-1";

Let’s inspect the results:

|            Method |     Mean |    Error |   StdDev | Rank | Allocated |
|------------------ |---------:|---------:|---------:|-----:|----------:|
|       TryGetValue | 11.85 ns | 0.223 ns | 0.198 ns |    1 |         - |
|       ContainsKey | 13.03 ns | 0.309 ns | 0.610 ns |    2 |         - |
| GetValueOrDefault | 14.04 ns | 0.257 ns | 0.343 ns |    3 |         - |

We can see that there is a small difference in efficiency between the three methods when we search with a key that is not included in our collection. The TryGetValue method has a mean time of 11.85 nanoseconds, the ContainsKey method has a mean time of 13.03 nanoseconds, and the GetValueOrDefault method has respectively a mean time of 14.04 nanoseconds.

As we expected, the TryGetValue method and the GetValueOrDefault method are the fastest extensions for returning a value from a dictionary using an existing search key. Τhe TryGetValue method appears to be a little more efficient for returning the default type when the key is not present. So when we want to choose between those two, we shall consider the return type and what is more convenient for our program. If we want to return a Boolean type, then the optimal method is the TryGetValue extension. If we want to return the value itself, the GetValueOrDefault method is the option.

Conclusion

In this article, we explored three possible methods to return a default value from a Dictionary collection when our search key is not included. Also, we explored what happens behind the scene for these extensions, and then we evaluated our solutions in terms of efficiency.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!