С# - нужна реализация IDictionary, которая позволит использовать нулевой ключ

В принципе, я хочу что-то вроде этого:

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

Есть ли встроенные в библиотеку базового класса, которые позволяют это? Предыдущий код генерирует исключение во время выполнения при добавлении нулевого ключа.

Спасибо

Ответ 1

Вы можете избежать использования null и создать специальный класс значений Singleton, который делает то же самое. Например:

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");

Этот подход не сработает, если вы намерены сделать вашу коллекцию более строго типизированной - скажем, например, вы хотите, чтобы ключ был строкой. Поскольку строка запечатана, вы не можете наследовать ее, чтобы создать замену "специального значения" для null. Ваши альтернативы становятся немного сложнее. Вы могли:

  • Создайте специальное значение константы для представления "пустого" / "нулевого" случая. Вид хаки и определенно путь к путанице. Это может быть жизнеспособным подходом, если словарь полностью закрыт для какого-либо класса реализации, и вы можете написать некоторые методы утилиты Encode/Decode, чтобы не распространять знания о том, как вы переводите ключи по всему месту.
  • Создайте собственную реализацию IDictionary, которая внутренне делегирует экземпляр Dictionary < > , за исключением случая null. Это нарушает документированные ожидания для интерфейса IDictionary < > , который говорит, что пустые ключи должны генерировать исключение. Но вы можете уйти от него, если это единственный способ решить вашу настоящую проблему. Это работает только в том случае, если вы владеете и создаете экземпляр словаря.
  • Найдите способ решить вашу проблему без сохранения "нулевого" ключа в словаре. Например, рассмотрите вопрос о том, чтобы не заполнять нулевой ключ в словаре и иметь некоторую специальную логику случая для решения этой проблемы. Ключи должны быть хешируемыми и сопоставимыми с работой с базовой реализацией, поэтому нуль запрещается в обычном режиме.

Как в стороне, действительно ли ваш словарь-ключ действительно нужен для ключа object? Это может привести к незначительным ошибкам из-за использования ссылочного равенства, когда вы можете предполагать, что Equals() оценивается как основа для сравнения.

Ответ 2

Как насчет этого?

public class NullableDictionnary<T1, T2> : Dictionary<T1, T2>
{
    T2 null_value;

    public T2 this[T1 key]
    {
        get
        {
            if (key == null)
            { return null_value; }
            return base[key];
        }
        set
        {
            if (key == null)
            { null_value = value; }
            else
            { base[key] = value; }
        }
    }
}

Ответ 3

NameValueCollection может принимать нулевой ключ, но не реализует IDictionary. Однако было бы довольно легко получить от DictionaryBase и предоставить Add/Remove/Indexers и т.д., Которые просто заменяют нуль чем-то встроенным, например:

class MyDictionary : DictionaryBase {
    private readonly object nullKey = new object();

    void Add(object key, string value) {
       if ( key == null ) { key = nullKey; }
       .. call base methods
    }

}

Ответ 4

Должен ли ключ буквально быть NULL? Ключ в коллекции работает как индекс. Мне не имеет большого смысла иметь NULL для индекса в коллекции.

Возможно, создайте новый класс


public class ObjectEntry
{
    public object objRef;
    public string desc;

    public ObjectEntry(object objectReference)
    {
        objRef = objectReference;
        if (objRef = null) {desc = "Nothing";}
        else {desc = objRef.Description;} //or whatever info you can get from a proper objRef value
    }
}

newObj = new ObjectEntry(null);
dict.add(newObj, newObj.desc);

Ответ 5

Нет необходимости в другой реализации Dicionary.

Взгляните на мой ответ здесь: fooobar.com/info/93713/...

Вы также сможете строго указать свой словарь:

var dict = new Dictionary<NullObject<int?>, string>();
dict[1] = "one int";
dict[null] = "null int";

Assert.AreEqual("one int", dict[1]);
Assert.AreEqual("null int", dict[null]);