Сегодня я столкнулся с этой ситуацией. У меня есть объект, который я тестирую на равенство; Создавание () метод возвращает реализацию подкласса 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;
}
Ключевое различие между ==
и 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
использовала ==
.
a == b проверяет, ссылаются ли они на один и тот же объект.
a.Equals (b) сравнивает содержимое.
Это ссылка на статью Джона Скита от 2004 года, которая объясняет это лучше.
Они оба делают то же самое, если только они специально не перегружены внутри объекта, чтобы делать что-то еще.
Цитата из статьи Джона Скита , упомянутой в другом месте.
Метод Equals - это просто виртуальный метод, определенный в System.Object, и переопределяемый теми классами, которые выберут для этого. Оператор == - это оператор , который может быть перегружен классами , но обычно имеет поведение идентичности .
Ключевое слово здесь ОБЫЧНО . Их можно написать так, чтобы они делали все, что пожелает базовый класс, и никоим образом не должны делать то же самое.
Я считаю, что a == b проверит, является ли объект, на который указывает ссылка, таким же.
Обычно, чтобы увидеть, совпадает ли значение, используется a.Equals (b) (это часто необходимо переопределить для работы).
Вы в значительной степени сами ответили на свой вопрос:
Я также переопределил Equals () в реализации подкласса, которая выполняет очень простую проверку увидеть, является ли переданный объект нулевым и имеет ли тип подкласса. Если оба этих условия соблюдены, объекты считаются равными.
Оператор ==
не был перегружен, поэтому он возвращает false
, поскольку a
и b
- разные объекты. Но a.Equals
вызывает ваше переопределение, которое предположительно возвращает true
, потому что ни a
, ни b
не имеют значения NULL, и они оба типа подкласса.
Итак, ваш вопрос был: "Когда a == b может быть ложным, а a.Equals (b) истинным?" Ваш ответ в этом случае: когда вы явно кодируете это так!
В Java a ==b проверяет, равны ли ссылки двух объектов (грубо, если два объекта являются одним и тем же объектом "aliased")
a.equals(b) сравнивает значения, представленные двумя объектами.
Операция "==" проверяет абсолютное равенство (если не перегружено); то есть он проверяет, являются ли два объекта одним и тем же объектом . Это верно только в том случае, если вы назначили одно другому, т.е.
MyObject a = MyObject.Create();
MyObject b = a;
Простая установка всех свойств двух объектов равными не означает, что сами объекты равны. Под капотом оператор "==" сравнивает адреса объектов в памяти. Практический эффект этого заключается в том, что если два объекта действительно равны, изменение свойства на одном из них также изменит его и на другом, тогда как если они только похожи («Равно» равны), этого не произойдет. Это будет совершенно последовательным, если вы поймете принцип.