Два равных объекта .NET не говорят, что они - PullRequest
14 голосов
/ 12 августа 2010

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

object val1 = 1;
object val2 = 1;

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

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

Ответы [ 7 ]

33 голосов
/ 12 августа 2010

Оператор == является статическим, а не виртуальным, поэтому поведение определяется статическим типом, а не типом времени выполнения. Реализация по умолчанию для == на объектах ссылочного типа заключается в сравнении ссылок (хотя типы могут реализовывать другое поведение, например string). У вас есть два разных объекта, и они не имеют одинаковую ссылку, поэтому == возвращает false.

Решение, как вы указываете, заключается в использовании 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.

10 голосов
/ 12 августа 2010

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

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

2 голосов
/ 12 августа 2010

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

Это все равно, что сравнивать два яблока.Оба - яблоки и выглядят одинаково, но это разные объекты.

1 голос
/ 12 августа 2010

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

0 голосов
/ 12 августа 2010

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

0 голосов
/ 12 августа 2010

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

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

val1 == val1; //Equals true

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

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

...