I'm working on a C# project on which, until now, I've used immutable objects and factories to ensure that objects of type Foo
can always be compared for equality with ==
.
Foo
objects can't be changed once created, and the factory always returns the same object for a given set of arguments. This works great, and throughout the code base we assume that ==
always works for checking equality.
Now I need to add some functionality that introduces an edge case for which this won't always work. The easiest thing to do is to overload operator ==
for that type, so that none of the other code in the project needs to change. But this strikes me as a code smell: overloading operator ==
and not Equals
just seems weird, and I'm used to the convention that ==
checks reference equality, and Equals
checks object equality (or whatever the term is).
Is this a legitimate concern, or should I just go ahead and overload operator ==
?
There's a big difference between overloading ==
and overriding Equals.
When you have the expression
if (x == y) {
The method that will be used to compare variables x and y is decided at compile time. This is operator overloading. The type used when declaring x and y is used to define which method is used to compare them. The actual type within x and y (i.e., a subclass or interface implementation) is irrelevant. Consider the following.
object x = "hello";
object y = 'h' + "ello"; // ensure it's a different reference
if (x == y) { // evaluates to FALSE
and the following
string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference
if (x == y) { // evaluates to TRUE
This demonstrates that the type used to declare the variables x and y is used to determine which method is used to evaluate ==.
By comparison, Equals is determined at runtime based on the actual type within the variable x. Equals is a virtual method on Object that other types can, and do, override. Therefore the following two examples both evaluate to true.
object x = "hello";
object y = 'h' + "ello"; // ensure it's a different reference
if (x.Equals(y)) { // evaluates to TRUE
and the following
string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference
if (x.Equals(y)) { // also evaluates to TRUE