Мне нужно использовать Dictionary
коллекции, в которых даны два экземпляра d1
и d2
, где каждый из них имеет одинаковое KeyValuePair
содержимое, которое может быть вставлено в любом порядке:
(d1 == d2)
оценивается как true
d1.GetHashCode ()
== d2.GetHashCode ()
Первое требование было легче всего выполнить с помощью SortedDictionar y
вместо обычного Dictionary
.
Второе требование необходимо, потому что у меня есть одна точка, где мне нужно сохранить Dictionary
- основной тип Dictionary
используется в качестве ключа для другого Dictionary
, и если HashCodes не оцениваются на основе идентичного содержимого, использование ContainsKey ()
не будет работать так, как я хочу (то есть: если в словарь уже вставлен элемент с ключом d1
, то dictionary.ContainsKey (d2)
должен оценивается как true
.
Для этого я создал новый объект class ComparableDictionary: SortedDictionary
и включил следующее:
public override int GetHashCode() {
StringBuilder str = new StringBuilder();
foreach (var item in this) {
str.Append(item.Key);
str.Append("_");
str.Append(item.Value);
str.Append("%%");
}
return str.ToString().GetHashCode();
}
В мои модульное тестирование, это соответствует критериям равенства и хэш-кодов. Однако, читая Рекомендации и правила для GetHashCode , я столкнулся со следующим:
Правило: целое число, возвращаемое GetHashCode, никогда не должно изменяться, пока объект содержится в структуре данных, которая зависит от хэш-кода. Остается стабильным
Допустимо, хотя и опасно, создавать объект, значение хэш-кода которого может изменяться по мере изменения полей объекта. Если у вас есть такой объект и вы помещаете его в хеш-таблицу, тогда код, который изменяет объект, и код, который поддерживает хеш-таблицу, должны иметь какой-то согласованный протокол, который гарантирует, что объект не будет мутировать, пока он находится в хеш-таблица. Как будет выглядеть этот протокол, зависит от вас.
Если хэш-код объекта может изменяться, пока он находится в хеш-таблице, очевидно, что метод Contains перестает работать. Вы помещаете объект в корзину № 5, изменяете его, и когда вы спрашиваете набор, содержит ли он измененный объект, он смотрит в корзину № 74 и не находит его.
Помните, объекты могут быть помещены в хэш таблицы способами, которых вы не ожидали. Многие операторы последовательности LINQ внутренне используют хэш-таблицы. Не подвергайте опасные мутации объекты при перечислении LINQ-запроса, который их возвращает!
Теперь Dictionary
используется только один раз в коде, в месте, где содержимое из всех коллекций ComparableDictionary
должны быть установлены. Таким образом, согласно этим рекомендациям, я думаю , что было бы приемлемо переопределить GetHashCode
, как это сделал я (полностью основывая его на содержимом словаря).
После этого введения мои вопросы следующие:
SortedDictionary
очень низка по сравнению с Dictionary
(а у меня могут быть сотни экземпляров объекта). Единственная причина использования SortedDictionary
заключается в том, что я могу выполнять сравнение на равенство на основе содержимого словаря, независимо от порядка вставки. Есть ли лучший способ выполнить это требование равенства без использования SortedDictionary
? GetHashCode
приемлемой с учетом требований? Несмотря на то, что он основан на изменяемом содержимом, я не думаю, что это должно представлять какой-либо риск, поскольку единственное место, где он используется (я думаю), - это после того, как содержимое было установлено. Примечание : while Я настраивал их с помощью Dictionary
или SortedDictionary
, я не привязан к этим типам коллекций. Основная потребность - это коллекция, которая может хранить пары значений и удовлетворять требованиям равенства и хеширования, определенным выше.