views:

750

answers:

3

I'm working on a C# project for 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 ==?

+6  A: 

I believe the standard is that for most types, .Equals checks object similarity, and operator == checks reference equality.

I believe best practice is that for immutable types, operator == should be checking for similarity, as well as .Equals. And if you want to know if they really are the same object, use .ReferenceEquals. See the C# String class for an example of this.

McKay
No. The 'standard' for reference types is for both Equals en == to return the same as RefernceEquals. It is discouraged to overload either for non-immutable types.
Henk Holterman
Also, be careful of nulls here. x.Equals(null) will throw an NRE if x is null, whereas null == x will work.
darthtrevino
'standard' is a common way to solve certain type of problem, if the 'standard' gets in the way, then it's not very good standard.
Bill Yang
Bill, but it is a very good standard. Would you like a type where `a != b` but the Collection classes think they are duplicates?
Henk Holterman
+3  A: 

For immutable types I don't think there is anything wrong with having == overloaded to support value equality. I don't think I'd override == without overriding Equals to have the same semantics however. If you do override == and need to check reference equality for some reason, you can use Object.ReferenceEquals(a,b).

See this Microsoft article for some useful guidelines: http://msdn.microsoft.com/en-us/library/ms173147.aspx

Mike Sackton
+9  A: 

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
Sam
This is a very important point, and it's something I came across later while I was testing out this. Since I needed `operator==` to depend on the run-time type, I defined an operator overload in the base class that called `Equals()`. Worked like a charm.(Then I redid the object model and tore the whole thing out. But that's a different story.)
JSBangs