Когда может == b быть ложью и a. Равняется (b) верный?

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

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

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

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

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

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

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

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

ОБНОВЛЕНИЕ Здесь является реализацией, Равняется (), согласно просьбе:

public override bool Equals(object obj) {
    return obj != null && obj is MyObjectSubclass;
}
25
задан alastairs 22 March 2010 в 17:23
поделиться

7 ответов

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

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

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

Post-question-edit edit

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

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

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

32
ответ дан 28 November 2019 в 21:08
поделиться

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

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

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

6
ответ дан 28 November 2019 в 21:08
поделиться

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

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

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

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

1
ответ дан 28 November 2019 в 21:08
поделиться

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

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

0
ответ дан 28 November 2019 в 21:08
поделиться

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

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

Оператор == не был перегружен, поэтому он возвращает false , поскольку a и b - разные объекты. Но a.Equals вызывает ваше переопределение, которое предположительно возвращает true , потому что ни a , ни b не имеют значения NULL, и они оба типа подкласса.

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

3
ответ дан 28 November 2019 в 21:08
поделиться

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

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

1
ответ дан 28 November 2019 в 21:08
поделиться

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

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

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

0
ответ дан 28 November 2019 в 21:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: