Когда a == b может быть ложным, а a.Equals (b) верным? - PullRequest
25 голосов
/ 22 марта 2010

Я столкнулся с этой ситуацией сегодня.У меня есть объект, который я проверяю на равенство;метод Create () возвращает реализацию подкласса MyObject.

MyObject a = MyObject.Create();
MyObject b = MyObject.Create();

a == b; // is false
a.Equals(b); // is true

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

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

Assert.AreEqual(MyObject.Create(), MyObject.Create()); // Green bar

, и ожидается ожидаемый результат.Поэтому я предполагаю, что NUnit использует a.Equals (b) под прикрытием, а не a == b, как я предполагал.

Примечание: Я программирую на смеси .NET и Java, поэтому я могу смешивать свои ожидания / предположения здесь.Однако я подумал, что a == b работает более последовательно в .NET, чем в Java, где вам часто приходится использовать equals () для проверки равенства.

ОБНОВЛЕНИЕ Вот реализация Equals () согласно запросу:

public override bool Equals(object obj) {
    return obj != null && obj is MyObjectSubclass;
}

Ответы [ 7 ]

32 голосов
/ 22 марта 2010

Разница между == и Equals в том, что == (как и все операторы) не является полиморфной , а Equals (как и любая виртуальная функция) -

По умолчанию ссылочные типы будут получать идентичные результаты для == и Equals, потому что они оба сравнивают ссылки. Также возможно совершенно по-разному кодировать логику вашего оператора и Equals, хотя это кажется бессмысленным. Самая большая проблема возникает при использовании оператора == (или любого другого) на более высоком уровне, чем объявлена ​​требуемая логика (другими словами, ссылка на объект как родительский класс, который либо явно не определяет оператор, либо определяет его по-другому чем истинный класс). В таких случаях логика для класса, на который он ссылается , используется для операторов, но логика для Equals исходит из любого класса, на самом деле объект является .

Я хочу категорически заявить, что, основываясь исключительно на информации в вашем вопросе, нет абсолютно никаких оснований думать или предполагать, что Equals сравнивает значения со ссылками . Создать такой класс довольно просто, но это , а не спецификация языка.

Редактирование после вопроса

Ваша реализация Equals вернет true для любого ненулевого экземпляра вашего класса . Хотя синтаксис заставляет меня думать, что это не так, вы можете путать ключевое слово is C # (которое подтверждает тип) с ключевым словом is в VB.NET (которое подтверждает ссылочное равенство). Если это действительно так, то вы можете сделать явное сравнение ссылок в C #, используя Object.ReferenceEquals(this, obj).

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

Кстати, ваш комментарий о NUnit с использованием Equals верен по той же причине; поскольку операторы не являются полиморфными, у определенного класса не будет возможности определить пользовательское поведение равенства, если функция Assert использует ==.

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

a == b проверяет, ссылаются ли они на один и тот же объект.

a.Equals (b) сравнивает содержимое.

Это ссылка на JonСтатья скита от 2004 года, которая объясняет это лучше.

3 голосов
/ 22 марта 2010

Вы в значительной степени сами ответили на свой вопрос:

Я также переопределил Equals () в реализации подкласса, которая выполняет очень простую проверку, чтобы увидеть, передан ли объектимеет значение null и относится к типу подкласса.Если оба эти условия выполнены, объекты считаются равными.

Оператор == не был перегружен - поэтому он возвращает false, поскольку a и bразные предметы.Но a.Equals вызывает ваше переопределение, которое, вероятно, возвращает true, потому что ни a, ни b не являются нулевыми, и они оба имеют тип подкласса.Когда a == b может быть ложным, а a.Equals (b) верным? "Ваш ответ в этом случае: когда вы явно кодируете это так!

1 голос
/ 22 марта 2010

Они оба делают одно и то же, если они специально не перегружены внутри объекта, чтобы сделать что-то еще.

Цитата из статьи Джона Скита , упомянутой в другом месте.

Метод Equals - это просто виртуальный определенный в System.Object, и переопределено любым классом сделать это. Оператор == является оператор, который может быть перегружен классы, но которые обычно имеют личностное поведение.

Ключевое слово здесь ОБЫЧНО . Их можно написать так, чтобы они делали все, что пожелает базовый класс, и они никоим образом не должны делать то же самое.

1 голос
/ 22 марта 2010

В Java a == b проверьте, равны ли ссылки двух объектов (грубо, если два объекта являются одинаковыми объектами с псевдонимом)

a.equals (b) сравнивает значения, представленные двумя объектами.

0 голосов
/ 22 марта 2010

Операция "==" проверяет абсолютное равенство (если не перегружено); то есть он проверяет, являются ли два объекта одним и тем же объектом . Это верно только в том случае, если вы присвоили одно другому, т.е.

MyObject a = MyObject.Create();
MyObject b = a;

Простая установка всех свойств двух объектов равными не означает, что сами объекты являются. Оператор "==" сравнивает адреса объектов в памяти. Практический эффект этого состоит в том, что если два объекта действительно равны, изменение свойства одного из них также изменит его для другого, тогда как, если они только похожи («равно» равно), это не будет. Это совершенно последовательно, если вы понимаете принцип.

0 голосов
/ 22 марта 2010

Я полагаю, что a == b проверит, является ли указанный объект идентичным.

Обычно, чтобы увидеть, является ли значение тем же a.Equals (b) используется (это часто нужно переопределить для работы).

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