Подтвердить что ты не робот

Когда может 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;
}
4b9b3361

Ответ 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;

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