No, this is a bad idea. While infinite recursion does not happen with this code, it is a constant threat when you have some instances of Equals()
delegating to others. (If you use this approach then I'd strongly suggest writing many unit tests to make sure that Equals()
does what you expect in all cases.)
Note that when a.Equals((object)b)
returns true, a.GetHashCode() == b.GetHashCode()
must also be true. If you cannot ensure that new WholeNumber(2)
and new Fraction(2, 4)
have the same hash code, then they should not compare as equal by Equals(object)
.
The practice I have adopted is that the Equals(object)
override only returns true if the argument's type is or derives from the type where the override is declared -- in this case, obj is WholeNumber
. If this is true but obj.GetType() != typeof(WholeNumber)
then I do call b.Equals(a)
so that the more-derived Equals()
gets priority.
If you need equality with cousin types, then that is where IEquatable<T>
comes in. In this case you would implement IEquatable<Fraction>
on WholeNumber
too, and it would make perfect sense to delegate to Fraction
's implementation of IEquatable<WholeNumber>.Equals()
to avoid duplicating that logic. (Providing an implicit conversion from WholeNumber
to Fraction
might be beneficial here, too.)