When dealing with dictionaries, a typical problem is when an operation attempts
to retrieve an element using a key that does not exist in the dictionary. In
.NET, a KeyNotFoundException
is raised, and that’s the desired behaviour in
most circumstances. Sometimes, however, you know that your program will
frequently try to retrieve keys that do not exist. In such cases, it is more
efficient to use the TryGetValue
method:
This method returns the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter is returned (source)
The devil hides in details. TryGetValue
returns the default value for the
type of the value
parameter. So, if you use TryGetValue
to look into
a dictionary of strings, null
is returned on a missing key. That is probably
ok in most cases. Howewer, if your logic requires a custom default value
instead, then you are out of luck. You have to set it yourself on TryGetValue
failure. A typical implementation would be:
var result = MyDictionary.TryGetValue("key", var out value)
? value
: "not found";
It is a minor annoyance but still a hassle. Our solution has always been
a homemade GetValueOrDefault
extension method, something like this:
public static TValue GetValueOrDefault<TKey, TValue>
(this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
{
return dictionary.TryGetValue(key, var out value)
? value
: defaultValue;
}
Usage:
var result = MyDictionary.GetValueOrDefault("key", "not found");
We’ve been using it since forever, and we are still using it even in recent projects.
Today, as I was looking at something only tangentially related, I learned that
our extension method is obsolete, and it’s been for a while. NetStandard
2.1 and NetCore 2 added a new extension method to the official API. It’s
called, you guessed it, GetValueOrDefault
. It extends
ÌReadOnlyDictionary<TKey, TValue>
, so it applies to all generic dictionaries,
which is cool.
We could continue with our extension method. It has the advantage of working across all .NET platforms, not just recent ones. Implementations are likely similar, and there’s probably little (if any) performance difference (I am too lazy to compare). With NETCore (now NET5), APIs have not only acquired cross-platform compatibility and improved performance but they have also been expanded and amended, something often not very apparent. Not to me, at least.
The point I want to make here, I think, is that nothing is set in stone. Today’s little event shows how my knowledge becomes stagnant over time. Setting apart the time to learn new things is good, but acquired ones need sharping too.