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

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

object val1 = 1;
object val2 = 1;

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

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

14
задан Peter Mortensen 13 July 2016 в 22:24
поделиться

7 ответов

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

33
ответ дан 1 December 2019 в 06:31
поделиться

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

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

10
ответ дан 1 December 2019 в 06:31
поделиться

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

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

2
ответ дан 1 December 2019 в 06:31
поделиться

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

1
ответ дан 1 December 2019 в 06:31
поделиться

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

val1 == val1; //Equals true

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

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

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

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

0
ответ дан 1 December 2019 в 06:31
поделиться

Если вы используете не объект , а собственный класс, вы можете переопределить операторы == и! = И, вероятно, должны реализовать интерфейс 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();
}
0
ответ дан 1 December 2019 в 06:31
поделиться

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
ответ дан 1 December 2019 в 06:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: