У меня есть следующий код:
object val1 = 1;
object val2 = 1;
bool result1 = (val1 == val2);//Equals false
bool result2 = val1.Equals(val2); //Equals true
Что с этим? Единственный способ исправить это с помощью метода .Equals()?
У меня есть следующий код:
object val1 = 1;
object val2 = 1;
bool result1 = (val1 == val2);//Equals false
bool result2 = val1.Equals(val2); //Equals true
Что с этим? Единственный способ исправить это с помощью метода .Equals()?
Оператор ==
является статическим, а не виртуальным, поэтому поведение определяется статическим типом, а не типом времени выполнения. Реализация по умолчанию для ==
для объектов ссылочного типа - это сравнение ссылок (хотя типы могут реализовывать другое поведение, например string
). У вас есть два разных объекта, и они не имеют одинаковой ссылки, поэтому ==
возвращает 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. И две ссылки не равны. Но равно сравнивает ссылочные значения вместо ссылок.
Два объекта равны, если они указывают на одно и то же пространство в памяти.
val1 == val1; //Equals true
Как указано tc, вы можете сделать перегрузку оператора.
public static bool operator ==(Object a, Object b)
Таким образом, поведение оператора ==
будет определяться этим методом.
Вы также должны перегрузить оператор !=
при перегрузке ==
.
Если вы не используете object
, а пользовательский класс, вы можете переопределить операторы == и!= и, возможно, должны реализовать интерфейс IEqualityComparer<T>
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 и сравнивает значения как целые числа, сравнение типов значений.