Когда может be == b быть false и a.Equals(b) true?
Сегодня я столкнулся с этой ситуацией. У меня есть объект, который я тестирую для равенства; метод Create() возвращает подкласс класса MyObject.
MyObject a = MyObject.Create();
MyObject b = MyObject.Create();
a == b; // is false
a.Equals(b); // is true
Примечание. Я также переопределил Equals() в реализации подкласса, который выполняет очень базовую проверку, чтобы проверить, является ли переданный объект нулевым и относится к типу подкласса. Если оба этих условия выполнены, объекты считаются равными.
Другая странная вещь: мой набор unit test выполняет некоторые тесты, похожие на
Assert.AreEqual(MyObject.Create(), MyObject.Create()); // Green bar
и ожидаемый результат наблюдается. Поэтому я предполагаю, что NUnit использует a.Equals(b) под обложками, а не a == b, как я предполагал.
Боковое примечание: Я программирую в формате .NET и Java, поэтому я мог бы смешать мои ожидания/предположения здесь. Я думал, однако, что a == b работал более последовательно в .NET, чем в Java, где вам часто приходится использовать equals() для проверки равенства.
UPDATE. Здесь выполняется реализация Equals():
public override bool Equals(object obj) {
return obj != null && obj is MyObjectSubclass;
}
Ответы
Ответ 1
Ключевое различие между ==
и Equals
заключается в том, что ==
(как и все операторы) не является полиморфным, а Equals
(как любая виртуальная функция).
По умолчанию ссылочные типы получат одинаковые результаты для ==
и Equals
, потому что они сравнивают ссылки. Конечно же, можно логически закодировать логику оператора и логику Equals
по-разному, хотя это кажется бессмысленным. Самый большой результат возникает при использовании оператора ==
(или любого) на более высоком уровне, чем объявлена желаемая логика (другими словами, ссылка на объект как родительский класс, который либо явно не определяет оператор, либо определяет его по-разному чем истинный класс). В таких случаях логика для класса, на которую он ссылается, используется для операторов, но логика для Equals
исходит из любого класса, на самом деле объекта.
Я хочу подчеркнуть, что, основываясь исключительно на информации в вашем вопросе, нет абсолютно никаких оснований думать или предполагать, что Equals
сравнивает значения по сравнению с ссылками. Тривиально легко создать такой класс, но это не спецификация языка.
Редактирование после вопроса-редактирования
Ваша реализация Equals
вернет значение true для любого непустого экземпляра вашего класса. Хотя синтаксис заставляет меня думать, что это не так, вы можете ввести в заблуждение ключевое слово is
С# (которое подтверждает тип) с ключевым словом is
в VB.NET(что подтверждает ссылочное равенство). Если это действительно так, то вы можете сделать явное сравнение ссылок в С# с помощью Object.ReferenceEquals(this, obj)
.
В любом случае, именно поэтому вы видите true
для Equals
, так как вы передаете ненулевой экземпляр вашего класса.
Кстати, ваш комментарий о NUnit с использованием Equals
верен по той же причине; потому что операторы не являются полиморфными, не будет никакого способа для определенного класса определить пользовательское поведение равенства, если используется функция Assert
==
.
Ответ 2
a == b проверяет, ссылаются ли они на один и тот же объект.
a.Equals(b) сравнивает содержимое.
Это ссылка в статью Jon Skeet от 2004 года, которая объясняет это лучше.
Ответ 3
Вы очень ответили на свой вопрос:
В реализации подкласса я также переопределял Equals(), который выполняет очень базовую проверку, чтобы проверить, является ли объект переданного объекта нулевым и относится к типу подкласса. Если оба этих условия выполнены, объекты считаются равными.
Оператор ==
не был перегружен - поэтому он возвращает false
, так как a
и b
- разные объекты. Но a.Equals
вызывает ваше переопределение, которое предположительно возвращает true
, потому что ни a
, ни b
не являются нулевыми, и они оба являются типами подкласса.
Итак, ваш вопрос: "Когда может быть == b false и a.Equals(b) true?" Ваш ответ в этом случае: когда вы явно кодируете его так!
Ответ 4
В Java a == b проверьте, равны ли ссылки двух объектов (грубо, если два объекта являются одним и тем же объектом "aliased" )
a.equals(b) сравнить значения, представленные этими двумя объектами.
Ответ 5
Они оба делают то же самое, если они специально не перегружены внутри объекта, чтобы сделать что-то еще.
Цитата из статья Джона Скита, упомянутая в другом месте.
Метод Equals - это просто виртуальный один, определенный в System.Object, и переопределяется тем, какие классы выбирают для этого. Оператор == является оператора, который может быть перегружен классов, но обычно идентичность.
Ключевое слово здесь USUALLY. Они могут быть написаны для того, чтобы делать то, что хочет основной класс, и ни в коем случае они не должны делать то же самое.
Ответ 6
Я считаю, что a == b проверяет, является ли ссылочный объект одинаковым.
Обычно, чтобы узнать, совпадает ли значение a.Equals(b) (это часто необходимо переопределить для работы).
Ответ 7
"==" проверяет абсолютное равенство (если не перегружено); то есть он проверяет, являются ли два объекта одним и тем же объектом. Это верно только в том случае, если вы назначили друг другу, т.е.
MyObject a = MyObject.Create();
MyObject b = a;
Просто установка всех свойств двух одинаковых объектов не означает, что сами объекты. Под капотом, что сравнивает оператор "==", являются адреса объектов в памяти. Практический эффект от этого состоит в том, что если два объекта действительно равны, изменение свойства на одном из них также изменит его на другом, тогда как если они будут только похожими ( "Равенство" равно), это не будет. Это понятно, если вы понимаете принцип.