В чем разница между == и Equals() для примитивов в С#?

Рассмотрим этот код:

int age = 25;
short newAge = 25;
Console.WriteLine(age == newAge);  //true
Console.WriteLine(newAge.Equals(age)); //false
Console.ReadLine();

Оба int и short являются примитивными типами, но сравнение с == возвращает true, а сравнение с Equals возвращает false.

Почему?

Ответ 1

Краткий ответ:

Равенство сложное.

Подробный ответ:

Примитивы переопределяют базу object.Equals(object) и возвращают значение true, если в коробке object имеет тот же тип и значение. (Обратите внимание, что он также будет работать для типов с нулевым значением, а ненулевые типы с нулевыми значениями всегда привязываются к экземпляру базового типа.)

Так как newAge является short, его метод Equals(object) возвращает true, если вы передаете коробочную короткую с тем же значением. Вы передаете коробку int, поэтому она возвращает false.

В отличие от этого оператор == определяется как взятие двух int (или short или long s).
Когда вы вызываете его с помощью int и short, компилятор будет неявно преобразовывать short в int и сравнивать полученный результат int по значению.

Другие способы заставить его работать

Примитивные типы также имеют свой собственный метод Equals(), который принимает тот же тип.
Если вы пишете age.Equals(newAge), компилятор выберет int.Equals(int) как лучшую перегрузку и неявно конвертирует short в int. Затем он вернет true, так как этот метод просто сравнивает int напрямую.

short также имеет метод short.Equals(short), но int не может быть неявно преобразован в short, поэтому вы его не вызываете.

Вы можете заставить его вызвать этот метод с помощью cast:

Console.WriteLine(newAge.Equals((short)age)); // true

Это вызовет short.Equals(short) напрямую, без бокса. Если age больше 32767, оно выдает исключение переполнения.

Вы также можете вызвать перегрузку short.Equals(object), но явно передать объект в коробке, чтобы он получил тот же тип:

Console.WriteLine(newAge.Equals((object)(short)age)); // true

Как и предыдущая альтернатива, это вызовет переполнение, если оно не соответствует short. В отличие от предыдущего решения, он помещает short в объект, теряя время и память.

Исходный код:

Ниже приведены методы Equals() из исходного кода:

    public override bool Equals(Object obj) {
        if (!(obj is Int16)) {
            return false;
        }
        return m_value == ((Int16)obj).m_value;
    }

    public bool Equals(Int16 obj)
    {
        return m_value == obj;
    }

Дальнейшее чтение:

См. Эрик Липперт.

Ответ 2

Потому что нет перегрузки для short.Equals, который принимает int. Поэтому это называется:

public override bool Equals(object obj)
{
    return obj is short && this == (short)obj;
}

obj не является short.. поэтому он неверен.

Ответ 3

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

Object.Equals
http://msdn.microsoft.com/en-us/library/bsc2ak47(v=vs.110).aspx

Ответ 4

Когда вы пройдете int до short Равно вы пройдете object:

enter image description here Итак, этот псевдокод работает:

return obj is short && this == (short)obj;

Ответ 5

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

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

int x=1;
short y=1;
x==y;//true
y.Equals(x);//false

в приведенном выше примере, X и Y имеют одинаковые значения, т.е. 1, и когда мы используем ==, он вернет true, как в случае ==, короткий тип преобразуется в int компилятором и результат.

и когда мы используем Equals, сравнение выполняется, но тип casting не выполняется компилятором, поэтому возвращается false.

Ребята, пожалуйста, дайте мне знать, если я ошибаюсь.

Ответ 6

Equals() - это метод System.Object Класс
Синтаксис: Открытый виртуальный bool Равно()
Рекомендация, если мы хотим сравнить состояние двух объектов, тогда мы должны использовать метод Equals()

как указано выше, ответы == сравнивают значения.

Пожалуйста, не путайтесь с ReferenceEqual

Опорные значения()
Синтаксис: public static bool ReferenceEquals()
Он определяет, имеют ли экземпляр указанных объектов один и тот же экземпляр

Ответ 7

Во многих контекстах, где аргумент метода или оператора не имеет требуемого типа, компилятор С# будет пытаться выполнить неявное преобразование типа. Если компилятор может заставить все аргументы удовлетворять свои операторы и методы путем добавления неявных преобразований, он будет делать это без жалобы, даже если в некоторых случаях (особенно с проверками равенства!) Результаты могут быть неожиданными.

Кроме того, каждый тип значения, такой как int или short, фактически описывает как тип значения, так и вид объекта (*). Существуют неявные преобразования для преобразования значений в другие типы значений и для преобразования любого вида значения в соответствующий тип объекта, но разные типы объектов неявно конвертируются друг в друга.

Если для сравнения a short и int используется оператор ==, short будет неявно преобразован в int. Если его числовое значение было равно значению int, int, к которому он был преобразован, будет равен int, с которым он сравнивается. Если попытаться использовать метод Equals для краткости, чтобы сравнить его с int, однако, единственным неявным преобразованием, которое удовлетворяло бы перегрузку метода Equals, было бы преобразование в тип объекта, соответствующий int. Когда вопрос short задан вопрос о том, совпадает ли он с объектом-передачей, он будет наблюдать, что рассматриваемый объект является int, а не short и, следовательно, заключает, что он не может быть равным.

В общем, хотя компилятор не будет жаловаться на него, следует избегать сравнения вещей, которые не одного типа; если вас интересует, приведет ли преобразование вещей в общую форму к одному и тому же результату, нужно явно выполнить такое преобразование. Рассмотрим, например,

int i = 16777217;
float f = 16777216.0f;

Console.WriteLine("{0}", i==f);

Существует три способа сравнения int с float. Можно было бы знать:

  • Соответствует ли ближайшее значение float значению int float?
  • Соответствует ли целочисленная часть float int?
  • Значения int и float представляют одинаковое числовое значение.

Если попытаться напрямую сравнить int и float, скомпилированный код ответит на первый вопрос; однако, то, что планировал программист, будет далеко не очевидным. Изменение сравнения с (float)i == f дало бы понять, что было предназначено первое значение, или (double)i == (double)f приведет к тому, что код ответит на третий вопрос (и разъяснит, что было предназначено).

(*) Даже если спецификация С# относится к типу типа, например. System.Int32 как объект типа System.Int32, такое представление противоречит требованию, чтобы код выполнялся на платформе, спецификация которой учитывает ценности и объекты как населяющие разные вселенные. Кроме того, если T является ссылочным типом, а x является T, то ссылка типа T должна иметь возможность ссылаться на x. Таким образом, если переменная v типа Int32 содержит Object, ссылка типа Object должна содержать ссылку на v или ее содержимое. Фактически, ссылка типа Object могла бы указывать на объект, содержащий данные, скопированные из v, но не на v и на его содержимое. Это означает, что ни v, ни его содержимое на самом деле не являются Object.

Ответ 8

Что вам нужно понять, так это то, что выполнение == всегда вызывает вызов метода. Вопрос в том, заканчивается ли вызов == и Equals вызовом/выполнением одних и тех же вещей.

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

EDIT: ответьте svick и добавьте комментарий SLaks, вот какой IL-код

int i1 = 0x22; // ldc.i4.s ie pushes an int32 on the stack
int i2 = 0x33; // ldc.i4.s 
short s1 = 0x11; // ldc.i4.s (same as for int32)
short s2 = 0x22; // ldc.i4.s 

s1 == i1 // ceq
i1 == s1 // ceq
i1 == i2 // ceq
s1 == s2 // ceq
// no difference between int and short for those 4 cases,
// anyway the shorts are pushed as integers.

i1.Equals(i2) // calls System.Int32.Equals
s1.Equals(s2) // calls System.Int16.Equals
i1.Equals(s1) // calls System.Int32.Equals: s1 is considered as an integer
// - again it was pushed as such on the stack)
s1.Equals(i1) // boxes the int32 then calls System.Int16.Equals
// - int16 has 2 Equals methods: one for in16 and one for Object.
// Casting an int32 into an int16 is not safe, so the Object overload
// must be used instead.

Ответ 9

== В примитивном

Console.WriteLine(age == newAge);          // true

В примитивном сравнении == оператор ведет себя довольно очевидно, в С# существует много перегрузок операторов ==.

  • строка == строка
  • int == int
  • uint == uint
  • long == long
  • еще много

Таким образом, в этом случае нет неявного преобразования от int до short, но возможно short to int. Таким образом, newAge преобразуется в int и происходит сравнение, которое возвращает true, поскольку оба значения имеют одинаковое значение. Таким образом, это эквивалентно:

Console.WriteLine(age == (int)newAge);          // true

.Equals() в примитиве

Console.WriteLine(newAge.Equals(age));         //false

Здесь мы должны увидеть, что такое метод Equals(), мы вызываем Equals с короткой переменной типа. Таким образом, существует три возможности:

  • Равные (объект, объект)//статический метод из объекта
  • Равные (объект)//виртуальный метод из объекта
  • Равные (короткие)//Реализует IEquatable.Equals(short)

Первый тип здесь не случай, так как количество аргументов различно, мы вызываем только один аргумент типа int. Третий также устраняется, как упоминалось выше, неявное преобразование int в short невозможно. Итак, здесь вызывается второй тип Equals(object). short.Equals(object):

bool Equals(object z)
{
  return z is short && (short)z == this;
}

Итак, здесь условие получило тестирование z is short, которое является ложным, так как z является int, поэтому возвращает false.

Вот подробная статья Эрика Липперта