Is there an IDictionary implementation that, on missing key, returns the default value instead of throwing?
Solution 1
Indeed, that won't be efficient at all.
As per comments, in .Net Core 2+ / NetStandard 2.1+ / Net 5, MS added the extension method GetValueOrDefault()
For earlier versions you can write the extension method yourself:
public static TValue GetValueOrDefault<TKey,TValue>
(this IDictionary<TKey, TValue> dictionary, TKey key)
{
TValue ret;
// Ignore return value
dictionary.TryGetValue(key, out ret);
return ret;
}
Or with C# 7.1:
public static TValue GetValueOrDefault<TKey,TValue>
(this IDictionary<TKey, TValue> dictionary, TKey key) =>
dictionary.TryGetValue(key, out var ret) ? ret : default;
That uses:
- An expression-bodied method (C# 6)
- An out variable (C# 7.0)
- A default literal (C# 7.1)
Solution 2
If you're using .NET Core 2 or above (C# 7.x), the CollectionExtensions class is introduced and you can use the GetValueOrDefault method to get default value if key is not there in a dictionary.
Dictionary<string, string> colorData = new Dictionary<string, string>();
string color = colorData.GetValueOrDefault("colorId", string.Empty);
Solution 3
Carrying these extension methods can help..
public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dict, K key)
{
return dict.GetValueOrDefault(key, default(V));
}
public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dict, K key, V defVal)
{
return dict.GetValueOrDefault(key, () => defVal);
}
public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dict, K key, Func<V> defValSelector)
{
V value;
return dict.TryGetValue(key, out value) ? value : defValSelector();
}
Solution 4
Collections.Specialized.StringDictionary
provides a non-exception result when looking up a missing key's value. It is also case-insensitive by default.
Caveats
It is only valid for its specialized uses, and — being designed before generics — it doesn't have a very good enumerator if you need to review the whole collection.
Solution 5
If you're using .Net Core, you can use the CollectionExtensions.GetValueOrDefault method. This is the same as the implementation provided in the accepted answer.
public static TValue GetValueOrDefault<TKey,TValue> (
this System.Collections.Generic.IReadOnlyDictionary<TKey,TValue> dictionary,
TKey key);
Related videos on Youtube
Comments
-
TheSoftwareJedi over 2 years
The indexer into
Dictionary
throws an exception if the key is missing. Is there an implementation ofIDictionary
that instead will returndefault(T)
?I know about the
TryGetValue()
method, but that's impossible to use with LINQ.Would this efficiently do what I need?:
myDict.FirstOrDefault(a => a.Key == someKeyKalue);
I don't think it will as I think it will iterate the keys instead of using a Hash lookup.
-
Rory O'Kane about 11 yearsSee also this later question, marked as a duplicate of this one, but with different answers: Dictionary returning a default value if the key does not exist
-
TheSoftwareJedi over 6 years@dylan That will throw an exception on missing key, not null. In addition it would require deciding what the default should be everywhere the dictionary is used. Also take note of the age of this question. We didn’t have the ?? operator 8 years ago anyhow
-
-
Jon Skeet over 15 yearsIt could be - but in some situations you may well know that it's not. I can see this being useful sometimes.
-
TheSoftwareJedi over 15 yearsIf you know null isn't in there - this is extremely nice to have. It makes joining these things in Linq (which is all I do lately) so much easier
-
MattDavey over 12 yearsBy using the ContainsKey method?
-
Peter Gluck over 11 yearsOr more compactly:
return (dictionary.ContainsKey(key)) ? dictionary[key] : default(TValue);
-
Jon Skeet over 11 years@PeterGluck: More compactly, but less efficiently... why perform two look-ups in the case when the key is present?
-
J Bryan Price over 11 years@JonSkeet: Thanks for correcting Peter; I've been using that "less efficient" method without realizing it for a while now.
-
MEMark about 10 yearsThe last overload is interesting. Since there is nothing to select from, is this simply a form of lazy evaluation?
-
nawfal about 10 years@MEMark yes value selector is run only if needed, so in a way it can be said as lazy evaluation, but its not deferred execution as in Linq context. But lazy evaluation here is not dependent on nothing to select from factor, you can of course make the selector
Func<K, V>
. -
Jon Coombs about 10 yearsYes, it's actually very useful. Python has this and I use it far more than the plain method, when I happen to be in Python. Saves writing a lot of extra if statements that are just checking for null result. (You're right, of course, that null is occasionally useful, but usually I'm wanting a "" or 0 instead.)
-
Jon Coombs about 10 yearsVery nice! I'm going to shamelessly plagiarize--er, fork it. ;)
-
Jon Coombs about 10 yearsIs that third method public because it's useful in its own right? That is, are you thinking someone might pass in a lambda that uses the current time, or a calculation based on... hmm. I would have expected to just have the second method do V value; return dict.TryGetValue(key, out value) ? value : defVal;
-
nawfal about 10 years@JCoombs right, the third overload is there for the same purpose. And ya of course you can do that in second overload, but I was making it a bit dry (so that I dont repeat logic).
-
Jon Coombs about 10 years@nawfal Good point. Staying dry is more important than avoiding one measly method call.
-
nawfal almost 10 yearsI had upvoted this. But if it was today I wouldnt have. Cant cancel now :). I upvoted the comments to make my point :)
-
piedar over 7 yearsThis has two lookups instead of one and it introduces a race condition if you're using ConcurrentDictionary.
-
jjaskulowski over 7 yearsThis is insignificant for this question. Besides, in many languages this is how standard types work and all is fine (ex. R)
-
theMayer about 5 yearsApparently MS decided this was good enough to add to
System.Collections.Generic.CollectionExtensions
, as I just tried and it's there. -
ianmac45 over 4 yearsFYI, @theMayer 's answer is only in .NET Core 2.0+, not the full Framework. But, still, a good find.
-
Per Lundberg over 3 yearsFor reference, the .NET 5 MSDN docs for this method is here: docs.microsoft.com/en-us/dotnet/api/…. There is also another convenient overload which lets you override the default value returned.
-
mkb over 3 yearsso we can use like this:
myDict[key]?.Name??""
? a usage sample would be great