У меня есть следующий код:
object val1 = 1;
object val2 = 1;
bool result1 = (val1 == val2);//Equals false
bool result2 = val1.Equals(val2); //Equals true
Что с этим? Единственный способ исправить это - использовать метод .Equals ()?
Оператор ==
является статическим, а не виртуальным, поэтому его поведение определяется статическим типом, а не типом времени выполнения. Реализация по умолчанию для ==
для объектов ссылочного типа заключается в сравнении ссылок (хотя типы могут реализовывать другое поведение, например строка
). У вас есть два разных объекта, и у них разные ссылки, поэтому ==
возвращает false.
Решение, как вы указываете, - использовать Equals. Equals - это виртуальный метод. Поскольку value1
имеет тип среды выполнения Int32
, вы в конечном итоге вызываете Int32.Equals . От .NET Reflector, вы можете видеть, что его реализация выглядит следующим образом:
public override bool Equals(object obj)
{
return ((obj is int) && (this == ((int) obj)));
}
Другими словами, он проверяет, имеет ли аргумент тип int
, и, если да, преобразует его и использует ==
, который определен для int
. Это сравнивает значений целых чисел.
Единственный способ исправить это - использовать метод .Equals ()?
Альтернативой является приведение ваших объектов к int
, а затем использование ==
, просто как и реализация Int32.Equals
.
Да. ==
проверяет равенство ссылок. Используйте Equals
, когда вы хотите сравнить содержимое.
Вы можете задаться вопросом, почему так происходит с объектами. Когда вы устанавливаете целое число (тип значения) в переменную объекта, происходит операция, называемая боксированием. Эта операция заворачивает тип значения в объект, помещает его в кучу и возвращает ссылку. Это происходит дважды, и ссылки становятся разными (хотя значения одни и те же).
==
проверяет, являются ли два объекта идентичными. Это не так. Они представляют одно и то же число, но хранятся в разных местах памяти.
Это как сравнить два яблока. Оба - яблоки и выглядят одинаково, но это разные объекты.
Это потому, что когда вы приводите их к объектам, они «конвертируются» в ссылки на значения типа int. И две ссылки не равны. Но equals сравнивает ссылочные значения вместо ссылок.
Два объекта равны, если они указывают на одно и то же место в памяти.
val1 == val1; //Equals true
Как указал tc, вы можете сделать перегрузку оператора.
public static bool operator ==(Object a, Object b)
Таким образом, поведение оператора ==
будет таким, как определено этим методом.
Вы также должны перегрузить оператор !=
, когда перегружаете ==
.
Если вы используете не объект
, а собственный класс, вы можете переопределить операторы == и! = И, вероятно, должны реализовать интерфейс IEqualityComparer
public static bool operator ==(MyType left, MyType right)
{
//code here, don't forget about NULLS when writing comparison code!!!
}
public static bool operator !=(MyType left, MyType right)
{
return !(left == right);
}
public bool Equals(MyType x, MyType y)
{
return (x == y);
}
public int GetHashCode(MyType obj)
{
return base.GetHashCode();
}
CIL для вашего кода объединяет два целых числа и сравнивает два объекта, которые являются результатом упаковки (==). Это сравнение для справки.
.locals init ([0] object val1,
[1] object val2,
[2] bool result1,
[3] bool result2)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: box [mscorlib]System.Int32
IL_0007: stloc.0
IL_0008: ldc.i4.1
IL_0009: box [mscorlib]System.Int32
IL_000e: stloc.1
IL_000f: ldloc.0
IL_0010: ldloc.1
IL_0011: ceq
IL_0013: stloc.2
IL_0014: ldloc.0
IL_0015: ldloc.1
IL_0016: callvirt instance bool [mscorlib]System.Object::Equals(object)
IL_001b: stloc.3
Для .Equals он вызывает Object.Equals, который вызывает Int32.Equals (вызов виртуального метода для Object):
public override bool Equals(object obj)
{
return ((obj is int) && (this == ((int) obj)));
}
Это приводит к типу int и сравнивает значения как целые числа, сравнение типов значений.