Словарь C # <> и изменяемые ключи - PullRequest
9 голосов
/ 09 июня 2010

Мне сказали, что одна из многих причин, по которым строки были сделаны неизменяемыми в спецификации C #, заключалась в том, чтобы избежать проблемы изменения ключей HashTables, когда ссылки на ключи строк изменяют их содержимое.Тип позволяет ссылочным типам использоваться в качестве ключа.Как словарь избегает проблемы измененных ключей, которые приводят к "неуместным" значениям?Есть ли членный клон, созданный из объекта при использовании в качестве ключа?

Ответы [ 5 ]

9 голосов
/ 09 июня 2010

Тип Dictionary<TKey,TValue> не пытается защитить пользователя от изменения используемого ключа.Ответственность за то, чтобы не поменять ключ, лежит на разработчике.

Если подумать немного, то это действительно единственный разумный путь, по которому Dictionary<TKey,TValue> может пойти.Рассмотрим значение выполнения операции, подобной элементному клону объекта.Чтобы быть точным, вам нужно выполнить глубокое клонирование, поскольку объект, на который есть ссылка в ключе, также может быть мутирован и, следовательно, влиять на хеш-код.Так что теперь каждый ключ, используемый в таблице, имеет полный клон объекта для защиты от мутаций.Это будет и глючное, и, возможно, очень дорогое действие.

8 голосов
/ 09 июня 2010

Если вы используете изменяемый ссылочный тип в качестве ключа, реализация по умолчанию GetHashCode() гарантирует равенство хеш-функции независимо от состояния объекта (т. Е. Хеш-код привязан к ссылке, а не к состоянию).Вы правы, однако, что изменчивый тип с семантикой равенства значений (где GetHashCode предположительно зависит от состояния) является плохим выбором для ключа словаря.

5 голосов
/ 09 июня 2010

Класс Dictionary<> не делает ничего, чтобы защитить себя от изменения изменяемого ключевого объекта. Вы должны знать, является ли класс, который вы используете в качестве ключа, изменчивым, и избегать его, если это возможно.

4 голосов
/ 30 сентября 2011

Если ссылочный тип не переопределяет Equals / GetHashCode, словарь, использующий компаратор по умолчанию, не будет заботиться о каких-либо полях или свойствах ключевых объектов и, следовательно, не будет замечать или заботиться об их изменении. Проще всего думать, что метод GetHashCode по умолчанию возвращает число, относящееся к «идентификатору объекта», а метод Equals по умолчанию сравнивает «идентификаторы объекта». Действительно, в системе, ограниченной двумя миллиардами или менее объектами, GetHashCode может просто возвращать идентификатор объекта, но по разным причинам он может выполнять и другие действия.

Если единственной частью объекта, которая проверяется Equals или GetHashCode, является идентификатор объекта, то для целей этих функций все объекты являются неизменяемыми. После создания объекта у него всегда будет один и тот же идентификатор, и этот идентификатор никогда не будет использоваться для других объектов, пока все следы прежнего идентификатора объекта не исчезнут из юниверса.

3 голосов
/ 09 июня 2010

Не избежать этой ситуации.Это требует вызывающий код:

Пока объект используется в качестве ключа в Dictionary<TKey, TValue>, он не должен изменяться каким-либо образом, который влияет на его хэш-значение.Каждый ключ в Dictionary<TKey, TValue> должен быть уникальным в соответствии со средством сравнения равенства словаря.Ключ не может быть null, но значение может быть, если тип значения TValue является ссылочным типом.

MSDN )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...