== или .Equals ()

Зачем использовать одно вместо другого?

Обратите внимание на то, что любой, кто ищет и находит этот ответ, может быть перегружен как Equals, так и ==, поэтому точные результаты вызова одного или другого будут отличаться. Например, string выполняет тест на равенство для ==. Также обратите внимание, что семантика обоих может быть сложный.

Guvante 01.10.2012 23:58

возможный дубликат Разница в C# между `==` и .Equals ()

Michael Freidgeim 27.08.2013 02:26

Согласно рекомендациям по проектированию Microsoft Framework: «ОБЯЗАТЕЛЬНО убедитесь, что Object.Equals и операторы равенства имеют одинаковую семантику и аналогичные характеристики производительности». docs.microsoft.com/en-us/dotnet/standard/design-guidelines/…

Dave Mackersie 18.12.2017 18:39
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
64
3
21 935
12
Перейти к ответу Данный вопрос помечен как решенный

Ответы 12

Ответ принят как подходящий

== - это проверка личности. Он вернет true, если два тестируемых объекта на самом деле являются одним и тем же объектом. Equals() выполняет проверку на равенство и вернет истину, если два объекта считают себя равными.

Проверка идентичности выполняется быстрее, поэтому ее можно использовать, когда нет необходимости в более дорогостоящих проверках на равенство. Например, сравнение с null или пустой строкой.

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


Как указано ниже: некоторые типы, такие как String или DateTime, предоставляют перегрузки для оператора ==, которые придают ему семантику равенства. Таким образом, точное поведение будет зависеть от типов сравниваемых объектов.


Смотрите также:

Как бы вы поступили с перегрузкой ==? Из любопытства.

Brettski 28.09.2008 01:42

@Brett: понятия не имею, но в блоге MSDN говорится, что это возможно.

John Millikin 28.09.2008 01:43

Фактически, FxCop заставляет вас переопределять Equals, если вы также переопределяете operator ==, поскольку они должны быть в основном такими же, в отличие от ReferenceEquals.

OregonGhost 28.09.2008 01:43

Как вы можете сказать, что никогда не должны отвергать Equals? Если ваши объекты равны, но созданы в разных частях приложения (скажем, одна и та же строка дважды извлекается из базы данных), вы можете сказать, что они одинаковы. Главное, чтобы Equals соответствовали идентичности объекта.

Oskar 28.09.2008 02:50

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

Matthew Scharley 28.09.2008 04:14

@Oskar: Я имею в виду, не переопределяйте, чтобы обеспечить необычное поведение. Например, не превращайте Equals () для типа значения в эталонное сравнение.

John Millikin 28.09.2008 09:54

строка s = "а"; строка r = "а"; int j = 0; int я = 0; если (s == r) j = 1; если (s.Equals (r)) i = 1; после того, как я выполню этот код, оба i и j имеют значение 1. Вы сказали: «Он вернет истину, если два тестируемых объекта на самом деле являются одним и тем же объектом», объекты s и r не совпадают, так почему это так?

Ozgur Dogus 28.06.2012 17:05

Поскольку String переопределяет оператор == и вызывает String.Equals (a, b), когда вы используете ==. Итак, s == r и s.Equals (r) делают то же самое для String. Проверить исходный код

Julien N 20.11.2014 14:34

Equals следует переопределить для типов с семантикой значения, и следует рассмотреть возможность перегрузки ==, чтобы тип больше походил на примитивный тип. Руководство по проектированию каркаса: docs.microsoft.com/en-us/dotnet/standard/design-guidelines/…docs.microsoft.com/en-us/dotnet/standard/design-guidelines/…

Dave Mackersie 18.12.2017 20:47

используйте equals, если вы хотите выразить, что содержимое сравниваемых объектов должно быть равно. используйте == для примитивных значений или если вы хотите проверить, что сравниваемые объекты являются одним и тем же объектом. Для объектов == проверяет, совпадает ли адресный указатель объектов.

== обычно "идентичность" означает, что "объект a фактически является тем же самым объектом в памяти, что и объект b".

equals () означает, что объекты логически равны (скажем, с точки зрения бизнеса). Поэтому, если вы сравниваете экземпляры определенного пользователем класса, вам обычно нужно использовать и определять equals (), если вы хотите, чтобы такие вещи, как Hashtable, работали правильно.

Если у вас был пресловутый класс Person со свойствами «Имя» и «Адрес», и вы хотели использовать это лицо в качестве ключа к хеш-таблице, содержащей дополнительную информацию о них, вам нужно было бы реализовать equals () (и хэш), чтобы вы может создать экземпляр Person и использовать его в качестве ключа в Hashtable для получения информации.

Используя только ==, ваш новый экземпляр нет будет таким же.

Согласно MSDN:

В C# существует два разных вида равенства: ссылочное равенство (также известное как идентичность) и равенство значений. Равенство значений - это общепринятый смысл равенства: это означает, что два объекта содержат одинаковые значения. Например, два целых числа со значением 2 имеют равенство значений. Ссылочное равенство означает, что нет двух объектов для сравнения. Вместо этого есть две объектные ссылки, и обе относятся к одному и тому же объекту.

...

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

Пример состоит в том, что класс DateTime реализует интерфейс IEquatable, который реализует «специфичный для типа метод определения равенства экземпляров». согласно MSDN.

Еще одна вещь, которую следует принять во внимание: оператор == может быть не вызываемым или может иметь другое значение, если вы обращаетесь к объекту с другого языка. Обычно лучше иметь альтернативу, которую можно назвать по имени.

Все остальные в значительной степени вас охватили, но у меня есть еще один совет. Время от времени вы будете встречать кого-то, кто клянется своей жизнью (и жизнями своих близких), что .Equals более эффективен / лучше / лучше всего подходит для некоторых других догматических высказываний. Я не могу говорить об эффективности (ну, хорошо, в определенных обстоятельствах я могу), но я могу поговорить о большой проблеме, которая возникнет: .Equals требует, чтобы объект существовал. (Звучит глупо, но людей это сбивает с толку.)

Вы не можете делать следующее:

StringBuilder sb = null;
if (sb.Equals(null))
{
    // whatever
}

Мне и, возможно, большинству людей кажется очевидным, что вы получите NullReferenceException. Однако сторонники .Equals забывают об этом маленьком факте. Некоторых даже "отбрасывают" (извините, не смог устоять), когда они видят, что NullRefs начинают всплывать.

(За годы до публикации DailyWTF я действительно работал с кем-то, кто уполномоченный, что все проверки равенства выполняются .Equals, а не ==. Даже доказательство его неточности не помогло. Мы просто чертовски постарались нарушить все остальные его правила, чтобы не было никаких ссылок возвращенный из метода, ни свойство никогда не было нулевым, и в конце концов это сработало.)

В этом конкретном случае вы можете использовать if (sb?.Equals(null) ?? true), но он определенно более громоздкий и менее читаемый, чем if (sb == null).

saluce 15.02.2017 22:49

В официальном совете по перегрузке Object.Equals(Object obj) упоминается явный возврат false для значений null из obj. В нем также указывается реализация исключения исключения не следует. Тем не менее, вы не можете гарантировать, что все последуют этому разумному совету! docs.microsoft.com/en-us/dotnet/api/system.object.equals

jmlane 14.11.2018 23:56

@ Джон Милликин:

Pointed out below: some value types like DateTime provide overloads for the == operator >that give it equality semantics. So the exact behavior will depend on the types of the >objects you are comparing.

Чтобы уточнить:

DateTime реализован как структура. Все структуры являются дочерними по отношению к System.ValueType.

Поскольку дочерние элементы System.ValueType живут в стеке, ссылочный указатель на кучу отсутствует, и, следовательно, нет возможности выполнить проверку ссылки, вы должны сравнивать объекты только по значению.

System.ValueType переопределяет .Equals () и == для использования проверки равенства на основе отражения, он использует отражение для сравнения значений каждого поля.

Поскольку отражение происходит несколько медленно, если вы реализуете свою собственную структуру, важно переопределить .Equals () и добавить свой собственный код проверки значений, так как это будет намного быстрее. Не вызывайте просто base.Equals ();

DateTime может находиться в куче или стеке. Если, например, он находится внутри класса, он будет жить в куче; По сути, два типа значений никогда не могут быть одинаковыми, если они передаются по значению, а не по ссылке, верно?

Luis Filipe 17.08.2013 04:32

Я видел Object.ReferenceEquals (), используемый в тех случаях, когда нужно знать, относятся ли две ссылки к одному и тому же объекту.

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

Например, string выполняет тест на равенство для ==.

Также обратите внимание, что семантика обоих может быть сложный.

Лучше всего реализовать равенство, как в этом примере. Обратите внимание, что вы можете упростить или исключить все это в зависимости от того, как вы планируете использовать свой класс, и что struct уже получает большую часть этого.

class ClassName
{
    public bool Equals(ClassName other)
    {
        if (other == null)
        {
            return false;
        }
        else
        {
            //Do your equality test here.
        }
    }

    public override bool Equals(object obj)
    {
        ClassName other = obj as null; //Null and non-ClassName objects will both become null
        if (obj == null)
        {
            return false;
        }
        else
        {
            return Equals(other);
        }
    }

    public bool operator ==(ClassName left, ClassName right)
    {
        if (left == null)
        {
            return right == null;
        }
        else
        {
            return left.Equals(right);
        }
    }

    public bool operator !=(ClassName left, ClassName right)
    {
        if (left == null)
        {
            return right != null;
        }
        else
        {
            return !left.Equals(right);
        }
    }

    public override int GetHashCode()
    {
        //Return something useful here, typically all members shifted or XORed together works
    }
}

Это не совсем правда. == перегружается, а Equals переопределяется, что является важным отличием. Таким образом, код, который выполняется для оператора ==, связывается во время компиляции, в то время как Equals является виртуальным и обнаруживается во время выполнения.

Stefan Steinegger 15.08.2013 10:58

@StefanSteinegger: Если вы не создаете библиотеки, вы редко столкнетесь с этим различием, я пошел дальше и добавил примечание.

Guvante 17.08.2013 04:11
"== перегружен, в то время как Equals переопределяется" -- Equals() can be both overloaded и overridden. I mean, obviously System.Object.Equals(object) can only be overridden. But there's nothing stopping a class from creating additional overloads of the Equals() method, and indeed this is what happens any time a class implements IEquatable<T>.
Peter Duniho 07.05.2015 03:10

Если вы дизассемблируете (например, с помощью dotPeek) Object, поэтому

public virtual bool Equals(Object obj)

описанный как:

// Returns a boolean indicating if the passed in object obj is
// Equal to this.  Equality is defined as object equality for reference
// types and bitwise equality for value types using a loader trick to
// replace Equals with EqualsValue for value types). 
//

Итак, это зависит от типа. Например:

        Object o1 = "vvv";
        Object o2 = "vvv";
        bool b = o1.Equals(o2);

        o1 = 555;
        o2 = 555;
        b = o1.Equals(o2);

        o1 = new List<int> { 1, 2, 3 };
        o2 = new List<int> { 1, 2, 3 };
        b = o1.Equals(o2);

Первый раз b является истинным (равное выполняется для типов значений), второй раз b истинно (равно выполняется для типов значений), третий раз b является ложным (равное выполняется для ссылочных типов).

В большинстве случаев они одинаковы, поэтому для ясности следует использовать ==. Согласно рекомендациям по проектированию Microsoft Framework:

«ДЕЛАТЬ гарантирует, что Object.Equals и операторы равенства имеют одинаковую семантику и аналогичные характеристики производительности». https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/equality-operators

Но иногда кто-то переопределяет Object.Equals без предоставления операторов равенства. В этом случае вы должны использовать Equals для проверки равенства значений и Object.ReferenceEquals для проверки ссылочного равенства.

Другие вопросы по теме