Разница между Object.Equals (objA, objB), objA.Equals (objB) и objA == objB для типов CLR? - PullRequest
4 голосов
/ 08 ноября 2011

Мне интересно, будут ли типы CLR возвращать разные результаты из следующих:

Object.Equals(objA, objB)

objA.Equals(objB)

(objA == objB)

Я понимаю, что за пределами CLR кто-то может легко реализовать оператор IEqualtable Equals и перегрузить оператор ==ненадлежащим образом.Я не обеспокоен тем, что люди неправильно реализуют их.Я согласен с тем, что классы (включая String, Int32 и т. Д.) Реализуют эти 3 по-разному.

Кроме того, какой из них должен использоваться для общего сравнения (по всем направлениям), если это возможно.Мне это интересно, потому что я наткнулся на файл, который использует Object.Equals(objA, objB) по всей модели представления вместо двух других.

private string _name;
public string Name
{
    get { return _name; }
    set
    {
        if (Equals(_name, value)) return;
        ...
    }
}

private int _id;
public int Id
{
    get { return _id; }
    set
    {
        if (Equals(_id, value)) return;
        ...
    }
}

private Object _obj;
public Object TheObject
{
    get { return _obj; }
    set
    {
        if (Equals(_obj, value)) return;
        ...
    }
}

Ответы [ 2 ]

6 голосов
/ 08 ноября 2011

Object.Equals (a, b) абсолютно безопасен.Он может ответить, например, Equals (null, null), что верно.Кроме того, он просто вызывает обычный метод Equals ().Насколько я знаю, для строковых и простых типов clr определены операторы равенства, которые работают точно так же, как Object.Equals (a, b).

Для ненулевых objA и objB, Object.Equals (objA, objB), objA.Equals (objB) и objB.Equals (objA) должны быть эквивалентны, если метод Equals реализован правильно.

Использование Equals (_obj, value) кажется правильным в опубликованном вами коде.

Если вы хотите получить полный список сравнений на равенство, не забывайте об objA.ReferenceEquals (objB)это своего рода равенство, которое полезно во многих сценариях.

1 голос
/ 08 ноября 2011

Для любого числа с плавающей запятой Equals и == ведут себя по-разному.

  • NaN==NaN => false в соответствии с логикой IEEE
  • NaN.Equals(NaN) => true Выполнение требования, что все должно быть равным себе.

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

Я почти никогда не звоню x.Equals(y) напрямую. С одной стороны, он не обрабатывает x, являясь null, и его асимметрия - это отвратительная ИМО. Статический object.Equals(x,y) вызывает виртуальный метод object.Equals(y), но добавляет обработку нуля.

IEquatable<T>.Equals(other) эквивалентно object.Equals(other) для всех типов с хорошим поведением, но позволяет избежать упаковки в типы значений.

В заключение я обычно предпочитаю ==, когда известен статический тип, и EqualityComparer<T>.Default с универсальными типами или, если статический тип не соответствует типу времени выполнения.


В вашем примере Name и Id ведут себя одинаково с == и Equals, поскольку string и int запечатаны.

TheObject, с другой стороны, демонстрирует различное поведение с == и Equals для определенных типов. Например, если вы используете string, тогда Equals будет использовать равенство значений, а == будет использовать равенство ссылок.

...