Два объекта .NET, которые равны, не говорят, что они

У меня есть следующий код:

object val1 = 1;
object val2 = 1;

bool result1 = (val1 == val2);//Equals false
bool result2 = val1.Equals(val2); //Equals true

Что с этим? Единственный способ исправить это с помощью метода .Equals()?

Ответ 1

Оператор == является статическим, а не виртуальным, поэтому поведение определяется статическим типом, а не типом времени выполнения. Реализация по умолчанию для == для объектов ссылочного типа - это сравнение ссылок (хотя типы могут реализовывать другое поведение, например 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.

Ответ 2

Да. == проверяет ссылочное равенство. Используйте Equals, где вы хотите сравнить содержимое.

Возможно, вам интересно, почему это происходит с объектами. Когда вы устанавливаете целое число (тип значения) в переменную объекта, происходит операция, называемая бокс. Эта операция переносит тип значения в объект и помещает его в кучу и возвращает ссылку. Это происходит дважды, и ссылки становятся разными (хотя значения одинаковы).

Ответ 3

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

Это похоже на сравнение двух яблок. Оба являются яблоками и выглядят одинаково, но это разные объекты.

Ответ 4

Это потому, что, когда вы бросаете их на объекты, они "преобразуются" в ссылки на значения int. И две ссылки не равны. Но равно сравнивает ссылочные значения вместо ссылок.

Ответ 5

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

val1 == val1; //Equals true

Как указано tc, вы можете сделать перегрузку оператора.

public static bool operator ==(Object a, Object b)

Таким образом, поведение оператора == будет определяться этим методом.

Вы также должны перегрузить оператор != при перегрузке ==.

Ответ 6

Если вы не используете 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();
}

Ответ 7

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 и сравнивает значения как целые числа, сравнение типов значений.