2011-01-07 2 views
1

Я планирую использовать несколько названных словарей в проекте. Мой первый выбор состоял в том, чтобы использовать ключ string, который является только свойством Name моих Value элементов.Тип безопасности для ключей словаря?

Однако, это делает ключи словаря идентичны, даже если они доступ к различным типам:

private Dictionary<string, Foo> myFoos; 
private Dictionary<string, Bar> myBars; 

myFoos[bar.Name]; // shouldn't be able to do this! 

Я хотел ключи быть типа несовместимы друг с другом, чтобы сделать их невозможно спутать друг с другом:

private Dictionary<FooName, Foo> myFoos; 
private Dictionary<BarName, Bar> myBars; 

Поскольку создание *Name класса для каждого типа Value является излишеством, я создал Name<T> класс:

public struct Name<T> 
{ 
    public string Name; 

    // for convenience, could be explicit instead 
    static implicit operator string(Name<T> name) 
    { 
     return name.Name; 
    } 
} 

, который дал бы мне

private Dictionary<Name<Foo>, Foo> myFoos; 
private Dictionary<Name<Bar>, Bar> myBars; 

и тогда я мог бы хранить Name<Foo> экземпляры вместо строк.

Это кажется немного громоздким, но это лучшее, что я придумал до сих пор - любые предложения о том, как это сделать лучше?
Является ли это ошибочным, или удивительным?

ответ

4

Первый вопрос:

Я хотел ключи быть типа несовместимы друг с другом, чтобы сделать их невозможно спутать друг с другом:

Почему? Есть ли вероятность путаницы? Это не очевидно. Имейте в виду, я не говорю, что ваш метод плох; на самом деле, по сути, есть, вероятно, реальные выгоды от этого. Но рассмотрите преобразователи массива:

int a[]; 
float b[]; 

Типы массивов несовместимы, но оба используют целочисленные индексы. И да, это может привести к проблемам, когда индексы запутаны - возможно, те же самые проблемы, с которыми вы сталкиваетесь с вашими ключами.

Так что этот случай в точности аналогичен вашему. Возможно, использование одних и тех же ключей для разных контейнеров не так уж и плохо (хотя в теории вы правы и существует риск путаницы).

+0

Проблема возникает, когда я хочу сохранить список баров, принадлежащих Foo. Вместо того, чтобы хранить вторую копию баров, я сохраняю Bar.Name - и словарь > начинает мутить воды. – mskfisher

+0

@mskfisher: это плохой подход. * Do * хранить бары напрямую, а не только их имена! Это * не * создание копий (если только ваши Foos и Bars не являются структурами, которых они не должны быть в этом случае). Если это классы, то их хранение не будет делать копии, оно просто будет хранить ссылки на объекты. Это фундаментальное свойство объектной ориентации, и ваш прецедент настолько распространен, что у него есть собственное имя: [агрегация] (http://en.wikipedia.org/wiki/Object_composition). –

+0

@ Konrad: Хорошая добыча, и еще одна вещь, о которой я должен был упомянуть. Я собираюсь переходить между структурами и классами этого проекта, так как я хочу передавать копии между потоками по значению, а не по ссылке. Теперь я просматриваю только классы и создаю конструктор копирования для каждого типа, который мне нужно передать между потоками. – mskfisher

5

Это будет работать, за исключением того, что вам нужно переопределить Equals и GetHashCode, чтобы сравнить имена по значению.