Разница между Object.Equals(objA, objB), objA.Equals(objB) и objA == objB для типов CLR?

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

Object.Equals(objA, objB)

objA.Equals(objB)

(objA == objB)

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

Решение

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

Для любого числа с плавающей запятой 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 будет использовать равенство значений, и == будет использовать ссылочное равенство.

Другие вопросы по тегам