Difference between Object.Equals(objA, objB), objA.Equals(objB) and objA == objB for CLR types?

1.1k views Asked by At

I am wondering if the CLR types would return different results from the following:

Object.Equals(objA, objB)

objA.Equals(objB)

(objA == objB)

I do realize that outside of the CLR someone could easily implement the IEqualtable Equals and overload the == operator improperly. I'm not concerned with people improperly implementing these. What I'm concerened with is the classes (including String, Int32, etc) implement these 3 differently.

Also, which one should be the one used for comparison overall (across the board) if that is possible. I wonder this because I ran across a file that uses Object.Equals(objA, objB) all over a view-model instead of the other two.

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

There are 2 answers

0
Anders Forsgren On BEST ANSWER

Object.Equals(a,b) is null safe. It can answer e.g. Equals(null, null) which is true. Apart from that, it just calls the regular Equals() method. As far as I know the clr string and primitive types have equality operators defined that work exactly like Object.Equals(a,b).

For non-null objA and objB, Object.Equals(objA, objB), objA.Equals(objB) and objB.Equals(objA) should be equivalent if the Equals method is correctly implemented.

The use of Equals(_obj, value) seems correct in the code you posted.

If you want the complete list of equality comparisons, don't forget about objA.ReferenceEquals(objB) which is a kind of equality that is useful in many scenarios.

0
CodesInChaos On

For any floating point number Equals and == behave differently.

  • NaN==NaN => false following IEEE logic
  • NaN.Equals(NaN) => true Follwing the requirement that anything must be equal to itself.

And of course Equals is overridden i.e. it works even when the static type is a base type, whereas == is overloaded and only works if the static type has been overloaded.

I almost never call x.Equals(y) directly. For one it doesn't handle a x being null, and it's asymmetry is ugly IMO. The static object.Equals(x,y) calls the virtual object.Equals(y) method, but adds null handling.

IEquatable<T>.Equals(other) is equivalent to object.Equals(other) on all well behaved types, but it avoids boxing in value types.

In conclusion I usually prefer == when the static type is known, and EqualityComparer<T>.Default with generic types or if the static type doesn't match the runtime type.


In your example Name and Id behave the same way with == and Equals, since string and int are sealed.

TheObject on the other hand exhibits different behavior with == and Equals for certain types. For example if you use string then Equals will use value equality, and == will use reference equality.