For any floating point number, Equals and == behave differently.
NaN==NaN => false after IEEE logicNaN.Equals(NaN) => true Follwing requires that something must be equal to itself.
And, of course, Equals redefined, i.e. works even if the static type is the base type, whereas == overloaded and only works if the static type has been overloaded.
I almost never call x.Equals(y) directly. For one, it does not handle x , which is null , and this asymmetry is an ugly IMO. The static object.Equals(x,y) calls the virtual object.Equals(y) method, but adds zero processing.
IEquatable<T>.Equals(other) equivalent to object.Equals(other) for all valid types, but it avoids boxing in value types.
In conclusion, I usually prefer == when the static type is known, and EqualityComparer<T>.Default with common types or if the static type does not match the runtime type.
In your example, Name and Id behave the same with == and Equals , since string and int sealed.
TheObject , on the other hand, has different behavior with == and Equals for certain types. For example, if you use string , then Equals will use the equality value, and == will use the reference equality.
source share