Why does Dictionary.ContainsKey throw ArgumentNullException?
Solution 1
If ContainsKey(null)
returned false
it would give the misleading impression that null keys are allowed..
Solution 2
This is how it is implemented: (Source)
public bool ContainsKey(TKey key) {
return FindEntry(key) >= 0;
}
And the method FindEntry
as:
private int FindEntry(TKey key) {
if( key == null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
}
if (buckets != null) {
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next) {
if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) return i;
}
}
return -1;
}
Since having a null
value as key in dictionary is not allowed.
Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary.Add(null, 10);
The above would produce an exception:
Value cannot be null. Parameter name: key
For your question:
Wouldn't it be more practical if it just returned false?
Someone from Microsoft could probably reply that. But IMO, since adding a null
value for key is not allowed there is no point in checking for null
key in ContainsKey
Related videos on Youtube
Marcin Kaczmarek
Updated on September 14, 2022Comments
-
Marcin Kaczmarek about 1 year
The documentation states that
bool Dictionary<TKey, TValue>.ContainsKey(TKey key)
throws an exception in case a null key is passed. Could anyone give a reason for that? Wouldn't it be more practical if it just returnedfalse
?-
Panagiotis Kanavos almost 10 yearsA null key is no value at all. It can never be used as a valid key so it can never be considered a valid input.
-
plinth almost 10 yearsWhat is the value of
null.GetHashCode()
? -
Servy almost 10 years@plinth it is whatever the
IEqualityComparer
says it is =p. It's actually entirely viable to choose to write a dictionary that accepts null keys, the library just didn't choose to do that. -
supercat almost 10 years@Luaan: Every generic type
T
must either be a reference type, in which case it may be directly compared tonull
, a nullable type, in which case comparison tonull
can be "compared" tonull
using aHasValue
check, or a structure type in which case a widening conversion will exist toT?
, which may then be "compared" tonull
. To actually box the key if it's a non-nullable value type would be a little silly; it would seem either the JIT should optimize that away or aNullChecker<T>.IsNull
method should be able to expedite the test.
-
-
supercat almost 10 yearsI expect the sole reason is probably that while
IEquatable<T>.GetHashCode(T)
could have been specified to return a constant when given a null value, it wasn't. If aDictionary
's call toIEquatable<T>
is going to throw an exception when given a null argument, it would be better to have the exception thrown fromDictionary
, giving the name of its parameter, than fromIEquatable<T>.GetHashCode()
.