Какова цель сделать Equals распространенным методом? - PullRequest
5 голосов
/ 03 декабря 2009

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

История гласит - у меня есть классы, объекты которых не сравнимы по умолчанию (в логическом смысле). Каждый раз, когда вы хотите сравнить / найти их, вы должны указать, как именно выполняется сопоставление. Лучшим в таком случае будет:

  1. нет такого вездесущего метода, как Equals, проблема решена, ни один программист (пользователь из моего класса) не попадет в ловушку, пропустив пользовательское совпадение при поиске

    но так как я не могу изменить C #

  2. скрыть унаследованные, нежелательные методы для предотвращения вызова (время компиляции)

    но это также потребует изменения на C #

  3. переопределить Equals и исключение выброса - по крайней мере, программист получает уведомление во время выполнения

Поэтому я спрашиваю, потому что я вынужден уродливым (с), потому что (б) не представляется возможным и из-за отсутствия (а).

Итак, вкратце - в чем причина того, что все объекты сравнимы (равны)? Для меня это одно предположение слишком далеко. Заранее спасибо за просветление: -).

Ответы [ 3 ]

7 голосов
/ 03 декабря 2009

Я согласен, что это было в основном ошибкой, как в .NET, так и в Java. То же самое верно для GetHashCode - наряду с каждым объектом, имеющим монитор.

Это имело бит больше смысла перед дженериками, по общему признанию - но с дженериками, переопределение Equals(object) всегда кажется довольно ужасным.

Я писал об этом некоторое время назад - вам могут понравиться как пост, так и комментарии.

2 голосов
/ 03 декабря 2009

Вы забыли вариант 4 .: Ничего не делать, пусть по умолчанию выполняется равенство ссылок. Ничего страшного, ИМО. Даже с вашими опциями соответствия вы можете выбрать опцию по умолчанию (я бы выбрал наиболее строгую опцию) и использовать ее для реализации Equals ().

0 голосов
/ 30 августа 2011

Предположим, у кого-то есть Список животных, и кто-то хочет сравнить два элемента друг с другом: экземпляр Кота и экземпляр Пса. Если экземпляр Cat спрашивается, совпадает ли он с экземпляром Dog, имеет ли смысл для кошки генерировать исключение InvalidTypeException или просто сказать «Нет, это не равно».

Предполагается, что метод Equals подчиняется двум правилам:

  1. Взаимность равенства: Для любых X и Y X.Equals (Y) будет истинным тогда и только тогда, когда Y.Equals (X) истинно.
  2. Принцип подстановки Лискова: если класс Q наследуется от P, операция, которая может быть выполнена с Q, также может быть выполнена с P.

Это вместе означает, что если Q происходит от P, то объект типа P должен иметь возможность вызывать Equals для объекта типа Q, что, в свою очередь, означает, что объект типа Q должен иметь возможность вызывать Равно для объекта типа P. Кроме того, если R также является производным от P, объект типа Q должен иметь возможность вызывать Equals для объекта типа R (независимо от того, связан ли R с Q).

Хотя для реализации всех объектов Equals может не быть строгой необходимости, для всех классов гораздо проще иметь один метод Equals (Object), чем использовать различные методы Equals для разных базовых типов, каждый из которых должен быть переопределен. с идентичной семантикой, чтобы избежать странного поведения.

Редактировать / Добавление

Object.Equals существует для ответа на вопрос: если две ссылки на объекты X и Y, может ли объект X обещать, что внешний код, который не использует ReferenceEquals, Reflection и т. Д., Не сможет показать, что X и Y не ссылаются к тому же экземпляру объекта? Для любого объекта X X.Equals (X) должен быть истинным, поскольку внешний код не может показать, что X не является тем же экземпляром, что и X. Кроме того, если X.Equals (Y) «законно» истинно, Y.Equals (X) ) также должно быть правдой; в противном случае тот факт, что X.Equals (X) (который является истинным) не соответствует Y.Equals (X), будет очевидной разницей, означающей, что X.Equals (Y) должен быть ложным.

Для мелкомутулируемых типов, если X и Y относятся к разным экземплярам объекта, это можно продемонстрировать, мутировав X и наблюдая, произошла ли та же самая мутация в Y (*). Если такую ​​мутацию можно использовать для демонстрации того, что X и Y являются разными экземплярами объекта, то X.Equals (Y) должен вернуть true. Причина того, что два объекта String, содержащие одинаковые символы, будут сообщать о себе равными друг другу, заключается не только в том, что они содержат одни и те же символы во время сравнения, но еще более важно, что если все экземпляры одного были заменены другим, то только код который использовал ReferenceEquals, Reflection или другие подобные трюки, даже заметил бы.

(*) Можно было бы иметь два разных, но неразличимых экземпляра X и Y мелко изменяемого класса, которые оба содержали ссылки друг на друга, так что методы, которые могли бы мутировать один, также мутировали бы другой. Если бы внешний код не мог отделить экземпляры друг от друга, можно на законных основаниях сообщить X.Equals (Y) об истинном (и наоборот). С другой стороны, я не могу представить, чтобы такой класс был более полезным, чем тот, в котором X и Y содержали неизменные ссылки на общий изменяемый объект. Обратите внимание, что X.Equals (Y) не требует, чтобы X и Y были глубоко неизменными; это просто требует, чтобы любые мутации, примененные к X, имели идентичный эффект на Y.

...