Переопределение метода экземпляра Object.Equals () в C #; теперь анализ кода / предупреждение FxCop CA2218: «также следует переопределить GetHashCode». Должен ли я подавить это? - PullRequest
5 голосов
/ 25 марта 2010

В моем проекте на C # есть сложный класс, в котором я хочу проводить тесты на равенство. Это не тривиальный класс; он содержит различные скалярные свойства, а также ссылки на другие объекты и коллекции (например, IDictionary). Что бы это ни стоило, мой класс запечатан.

Чтобы включить оптимизацию производительности в других частях моей системы (оптимизация, позволяющая избежать дорогостоящего обхода сети), мне нужно иметь возможность сравнивать экземпляры этих объектов друг с другом для равенства & ndash; кроме встроенного ссылочного равенства & ndash; и поэтому я переопределяю метод экземпляра Object.Equals (). Однако теперь, когда я это сделал, в FxCop анализа кода Visual Studio 2008. a.k.a, который я оставляю включенным по умолчанию, выдается следующее предупреждение:

предупреждение: CA2218: Microsoft.Usage: начиная с MySuperDuperClass переопределяет Equals, также следует переопределить GetHashCode.

Мне кажется, я понимаю обоснование этого предупреждения: Если Я собираюсь использовать в коллекции такие объекты, как ключ , хеш-код это важно. то есть см. этот вопрос . Однако я не собираюсь использовать эти объекты в качестве ключа в коллекции. Когда-либо.

Чувствуя себя оправданным для подавления предупреждения, я посмотрел код CA2218 в документации MSDN , чтобы получить полное имя предупреждения, чтобы я мог применить атрибут SuppressMessage к своему классу следующим образом:

    [SuppressMessage("Microsoft.Naming",
        "CA2218:OverrideGetHashCodeOnOverridingEquals",
        Justification="This class is not to be used as key in a hashtable.")]

Однако, читая дальше, я заметил следующее:

Как исправить нарушения

Чтобы исправить нарушение этого правила, обеспечить реализацию GetHashCode. Для пары объектов того же типа, вы должны убедиться, что реализация возвращает то же самое значение, если ваша реализация равно возвращает true для пары.

Когда следует подавлять предупреждения

-----> Не подавлять предупреждение от этого правило. [стрелка и акцент мой]

Итак, я хотел бы знать: Почему бы мне не подавить это предупреждение, как я планировал? Разве мой случай не требует подавления? Я не хочу кодировать реализацию GetHashCode () для этого объекта, который никогда не будет вызываться, так как мой объект никогда не будет ключом в коллекции. Если бы я хотел быть педантичным, а не подавлять, было бы разумнее переопределить GetHashCode () с реализацией, которая выдает исключение NotImplementedException?


Обновление: Я только что снова посмотрел эту тему в хорошей книге Билла Вагнера Эффективное C # , и он заявляет в "Item 10: Understapits GetHashCode ()":

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

... вот откуда у меня возникла мысль, что мне не нужно беспокоиться о GetHashCode () всегда.

Ответы [ 5 ]

14 голосов
/ 25 марта 2010

Если вы действительно reallio-trulio absosmurfly положительный , что вы никогда не будете использовать это как ключ к хеш-таблице, тогда ваше предложение обоснованно. Переопределить GetHashCode; заставить его выбросить исключение.

Обратите внимание, что хеш-таблицы прячутся в самых неожиданных местах. Множество операторов последовательности LINQ внутренне используют реализации хеш-таблиц для ускорения процесса. Отказываясь от реализации GetHashCode, вы также отказываетесь от возможности использовать ваш тип в различных запросах LINQ. Мне нравится создавать алгоритмы, которые используют запоминание для увеличения скорости; памятники обычно используют хеш-таблицы. Поэтому вы также отказываетесь от возможности запоминать вызовы методов, которые принимают ваш тип в качестве параметра.

В качестве альтернативы, если вы не хотите быть таким грубым: Override GetHashCode; сделайте так, чтобы он всегда возвращал ноль. Это соответствует семантическим требованиям GetHashCode; что два равных объекта всегда имеют одинаковый хэш-код. Если он когда-либо будет использоваться в качестве ключа в работе словаря, это будет ужасно, но вы можете справиться с этой проблемой, когда она возникнет, чего, как вы утверждаете, никогда не будет.

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

6 голосов
/ 25 марта 2010

Вы не должны подавлять это. Посмотрите, как реализован ваш метод equals. Я уверен, что он сравнивает одного или нескольких членов в классе, чтобы определить равенство. Часто одного из этих членов достаточно, чтобы отличить один объект от другого, и поэтому вы можете реализовать GetHashCode, вернув membername.GetHashCode();.

5 голосов
/ 25 марта 2010

Как только вы забудете, или другой разработчик, который не знает, использует это, у кого-то будет болезненная ошибка, чтобы отследить. Я бы порекомендовал просто правильно реализовать GetHashCode, и тогда вам не придется об этом беспокоиться. Или просто не используйте Equals для вашего специального сравнения сравнения.

5 голосов
/ 25 марта 2010

Мой $ 0,10 стоит? Реализуйте GetHashCode.

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

4 голосов
/ 25 марта 2010

Методы GetHashCode и Equals работают вместе, чтобы обеспечить семантику равенства на основе значений для вашего типа - вы должны реализовать их вместе.

Для получения дополнительной информации по этой теме, пожалуйста, смотрите следующие статьи:

Бесстыдная заглушка: эти статьи были написаны мной.

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