I come across this thread some days ago and needed a well thought out and clever solution to handle null keys. I took the time and implemented one by me to handle more scenarios.
You can find my implementation of NullableKeyDictionary currently in my pre-release package Teronis.NetStandard.Collections (0.1.7-alpha.37).
Implementation
public class NullableKeyDictionary : INullableKeyDictionary, IReadOnlyNullableKeyDictionary, IReadOnlyCollection, ValueType>> where KeyType : notnull
public interface INullableKeyDictionary : IDictionary, IDictionary, ValueType> where KeyType : notnull
public interface IReadOnlyNullableKeyDictionary : IReadOnlyDictionary, IReadOnlyDictionary, ValueType> where KeyType : notnull
Usage (Excerpt of the Xunit test)
// Assign.
var dictionary = new NullableKeyDictionary();
IDictionary nonNullableDictionary = dictionary;
INullableKeyDictionary nullableDictionary = dictionary;
// Assert.
dictionary.Add("value");
/// Assert.Empty does cast to IEnumerable, but our implementation of IEnumerable
/// returns an enumerator of type .
/// So we test on correct enumerator implementation wether it can move or not.
Assert.False(nonNullableDictionary.GetEnumerator().MoveNext());
Assert.NotEmpty(nullableDictionary);
Assert.Throws(() => dictionary.Add("value"));
Assert.True(dictionary.Remove());
Assert.Empty(nullableDictionary);
dictionary.Add("key", "value");
Assert.True(nonNullableDictionary.GetEnumerator().MoveNext());
Assert.NotEmpty(nullableDictionary);
Assert.Throws(() => dictionary.Add("key", "value"));
dictionary.Add("value");
Assert.Equal(1, nonNullableDictionary.Count);
Assert.Equal(2, nullableDictionary.Count);
The following overloads exists for Add(..):
void Add([AllowNull] KeyType key, ValueType value)
void Add(NullableKey key, [AllowNull] ValueType value)
void Add([AllowNull] ValueType value); // Shortcut for adding value with null key.
This class should behave same and intuitive as the dictionary does.
For Remove(..) keys you can use the following overloads:
void Remove([AllowNull] KeyType key)
void Remove(NullableKey key)
void Remove(); // Shortcut for removing value with null key.
The indexers do accept [AllowNull] KeyType or NullableKey. So supported scenarios, like they are stated in other posts, are supported:
var dict = new NullableKeyDictionary
dict[typeof(int)] = "int type";
dict[typeof(string)] = "string type";
dict[null] = "null type";
// Or:
dict[NullableKey.Null] = "null type";
I highly appreciate feedback and suggestions for improvements. :)