Поиск коллекции;альтернатива словарю
-
20-08-2019 - |
Вопрос
Класс TimeSheetActivity имеет коллекцию распределений.Распределение - это объект значения, который также используется другими объектами в домене и выглядит примерно так:
public class Allocation : ValueObject
{
public virtual StaffMember StaffMember { get; private set; }
public virtual TimeSheetActivity Activity { get; private set; }
public virtual DateTime EventDate { get ... }
public virtual TimeQuantity TimeSpent { get ... }
}
Повторяющиеся выделения для одного и того же выделения.Дата события не допускается.Таким образом, когда клиент пытается выполнить выделение для действия, выполняется проверка, чтобы увидеть, есть ли уже выделение в коллекции для такого же выделения.EventDate.Если нет, то новое распределение добавляется в коллекцию, но если это так, существующее распределение заменяется новым.
В настоящее время я использую словарь для поддержания коллекции с выделением.EventDate в качестве ключа.Это отлично работает для домена, но мне интересно, не является ли тот факт, что ключ уже является частью значения, сам по себе "плохим запахом".
У меня также нет причин сохранять что-либо, кроме значений словаря.Поскольку я использую NHibernate, мне может понадобиться написать какой-нибудь пользовательский тип для этого, и мне интересно, не является ли это также признаком того, что мне следует использовать другой тип коллекции.(Это также является причиной виртуальных свойств в классе распределения).
Основной альтернативой, о которой я думаю, был бы HashSet с выделенным EqualityComparer .
А ты как думаешь?
Приветствую, Беррил
Решение
Если вы используете внешний компаратор для выполнения HashSet<Allocation>
, вам нужно было бы быть очень осторожным, чтобы не изменять дату без повторного ввода значения в словаре.У вас есть эта проблема в любом случае, но она усугубляется изменчивостью (по крайней мере, с Dictionary<,>
он по-прежнему сможет отслеживать свои собственные ключи и значения).Используя изменяемое значение как часть ключа, вы рискуете никогда больше не увидеть это значение...
Когда я работал над системами расписания в прошлом, я действительно использовал SortedList<,>
для этого - аналогично, но полезно, если вам обычно нужны данные в последовательности, и позволяет выполнять двоичный поиск, если данные достаточно однородны.
Другие советы
Я не думаю, что тот факт, что ключ является частью значения, обязательно является проблемой.По моему опыту, это довольно часто случается со словарями.A HashSet
с соответствующим средством сравнения равенства, безусловно, сработало бы, при условии, что вам никогда не нужно было обращаться к текущему объекту с определенным EventDate
.Потенциально это кажется полезной вещью, которую нужно уметь делать...
Вы в настоящее время просто обеспокоены несколько смутно, или у вас есть конкретные подозрения относительно того, как это может вас задеть?
Используя стандартные библиотеки, я не знаю лучшего решения, чем это.Тем не менее, я также почувствовал, что от такого кода "дурно пахнет", но это из-за классов коллекции в BCL, а не вашего кода.
Я не знаю, почему MS не создала универсальные наборы<TKey, TData> where TData: IKeyed<TKey>
или так вместо Словарей, потому что это позволило бы реализовать такие структуры данных, где ключ является частью данных.В KeyValuePair<TKey, TValue>: IKeyed<TKey>
это была бы просто вспомогательная структура, реализующая этот интерфейс и, таким образом, позволяющая создавать идентичные функциональные возможности словаря в том виде, в каком мы имеем его сейчас.
Также (чтобы продолжить небольшую тираду) Интересно, почему они не добавили понятие декларативных неизменяемых типов и не сделали это возможным ограничением универсального типа, потому что это позволило бы убедиться, что ключ не изменяет свой хэш-код во время выполнения (что может произойти в настоящее время, если реализовать GetHashCode()
и Equals()
на каком-то изменяемом объекте).