В чем разница между == и 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
:
Итак, этот псевдокод работает:
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.
Вот подробная статья Эрика Липперта