2009-12-16 3 views
13

В принципе, я хочу что-то вроде этого:C# - Нужна IDictionary реализация, которая позволит пустой ключ

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

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

Благодаря

+0

Просто интересно, где вам это нужно? Спасибо –

ответ

11

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

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. Ваши альтернативы становятся немного сложнее. Вы можете:

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

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

+0

Приложение для этого компонента. Один пользовательский элемент управления C1FlexGrid.ImageMap, который в основном предназначен для сопоставления значений, хранящихся в сетке, с изображением. В принципе, я не контролирую данные, некоторые из них являются нулевыми. – Clyde

+0

Так что, к сожалению, я не могу использовать макет объекта, как предложение Nothing. – Clyde

+0

Однако, спасибо за предупреждение == vs Equals .... вы просто спасли меня некоторое время, отслеживая другую проблему. – Clyde

2

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

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

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

} 
5

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

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; } 
     } 
    } 
} 
+8

Будьте осторожны со всеми другими функциями, которые вы сейчас признали недействительными - подсчитываете, добавляете, очищаете, ContainsKey, ContainsValue и т. Д. Я имею в виду, если вы просто взламываете, ладно, но мне не нравится идея создания Класс «NullableDictionary», если вы собираетесь это сделать. Когда взломать, безусловно, взломать, вы с меньшей вероятностью получите немного позже. – phillipwei

+1

Это не компилируется - требуемые методы в '' Dictionary '' не являются виртуальными. Вы должны сделать это как отдельный адаптер, который реализует '' IDictionary ''. –

0

Действительно ли ключ должен быть 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); 
0

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

Взгляните на мой ответ здесь: https://stackoverflow.com/a/22261282/212272

Вы также сможете сохранить ваш словарь сильно типизированных:

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