Difference between Object.Equals(objA, objB), objA.Equals(objB) and objA == objB for CLR types?
-
24-02-2021 - |
Question
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;
...
}
}
La solution
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.
Autres conseils
For any floating point number Equals
and ==
behave differently.
NaN==NaN => false
following IEEE logicNaN.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.