Why Doesn't Dictionary<Tkey, Tvalue> Support Null Key

Why doesn't DictionaryTKey, TValue support null key?

It just hit me that your best answer is probably to just keep track of whether a default case has been defined:

class Switch
{
private Dictionary<Type, Action<object>> _dict;
private Action<object> defaultCase;

public Switch(params KeyValuePair<Type, Action<object>>[] cases)
{
_dict = new Dictionary<Type, Action<object>>(cases.Length);
foreach (var entry in cases)
if (entry.Key == null)
defaultCase = entry.Value;
else
_dict.Add(entry.Key, entry.Value);
}

public void Execute(object obj)
{
var type = obj.GetType();
if (_dict.ContainsKey(type))
_dict[type](obj);
else if (defaultCase != null)
defaultCase(obj);
}

...

The whole rest of your class would remain untouched.

Why can't you use null as a key for a Dictionarybool?, string?

It would tell you the same thing if you had a Dictionary<SomeType, string>, SomeType being a reference type, and you tried to pass null as the key, it is not something affecting only nullable type like bool?. You can use any type as the key, nullable or not.

It all comes down to the fact that you can't really compare nulls. I assume the logic behind not being able to put null in the key, a property that is designed to be compared with other objects is that it makes it incoherent to compare null references.

If you want a reason from the specs, it boils down to a "A key cannot be a null reference " on MSDN.

If you want an exemple of a possible workaround, you can try something similar to Need an IDictionary implementation that will allow a null key

How to avoid null key errors in dictionary?

Use TryGetValue:

Dictionary<int, string> dict = ...;
string value;

if (dict.TryGetValue(key, out value))
{
// value found
return value;
}
else
{
// value not found, return what you want
}

Need an IDictionaryTKey,TValue implementation that will allow a null key

You could avoid using null and create a special singleton value class that does the same thing. For example:

public sealed class Nothing
{
public static readonly Nothing Value = new Nothing();
private Nothing() {}
}

Dictionary<object, string> dict = new Dictionary<object, string>();
dict.add(Nothing.Value, "Nothing");
dict.add(1, "One");

This approach will fail to work if you intend to make your collection more strongly typed - let's say for example you want the key to be a string. Since string is sealed you can't inherit from it to create a "special value" substitute for null. Your alternatives become a bit more complicated. You could:

  1. Create some special constant value to represent the "empty" / "null" case. Kind of hacky and definitely a path to confusion. This can be a viable approach if the dictionary is completely private to some implementation class and you can write some Encode/Decode utility methods to avoid spreading the knowledge of how you translate keys all over the place.
  2. Create your own implementation of IDictionary that internally delegates to a Dictionary<> instance - except for the case of null. This violates the documented expectations for the IDictionary<> interface which does say that null keys should throw an exception. But you may be able to get away with it if it's the only way to solve your real problem. This only works if you own and create the dictionary instance.
  3. Find a way to solve your problem without storing a "null" key in the dictionary. For example, consider not populating the null key in the dictionary and having some special case logic to deal with it. Keys have to be hashable and comparable to work with the underlying implementation, which is why null is prohibited normally.

As an aside, does your dictionary key really need the key to be object? This can lead to subtle bugs due to reference equality being used where you may have intended Equals() to be evaluated as the basis for comparison.

How is this DictionaryTKey, TValue exception possible?

I've had this problem happen frequently because I made the mistake of allowing multiple threads to access the same dictionary. Make sure that this is not the case, because Dictionary is not thread-safe.

(Incidentally, your method can be greatly simplified. Dictionary<K,V> is already an IEnumerable<KeyValuePair<K,V>>. You should be able to just do ToArray on one.

How to get null instead of the KeyNotFoundException accessing Dictionary value by key?

In the end I came up with a variant using a deriving from dictionary class with explicit interface implementation:

public interface INullValueDictionary<T, U>
where U : class
{
U this[T key] { get; }
}

public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
where U : class
{
U INullValueDictionary<T, U>.this[T key]
{
get
{
U val;
this.TryGetValue(key, out val);
return val;
}
}
}

So it exposes the functionality I need the following way:

//create some dictionary
NullValueDictionary<int, string> dict = new NullValueDictionary<int, string>
{
{1,"one"}
};
//have a reference to the interface
INullValueDictionary<int, string> idict = dict;

try
{
//this throws an exception, as the base class implementation is utilized
Console.WriteLine(dict[2] ?? "null");
}
catch { }
//this prints null, as the explicit interface implementation
//in the derived class is used
Console.WriteLine(idict[2] ?? "null");

Why does Dictionary.ContainsKey throw ArgumentNullException?

If ContainsKey(null) returned false it would give the misleading impression that null keys are allowed..



Related Topics



Leave a reply



Submit