How difficult can it be to overload operator ==?

Well apparently very difficult! Today, I read article after article on blogs that suggested weird and wonderful ways of overloading the operator == in C#. Almost all of those were incorrect! So I set myself a challenge to put the record straight:

Before showing you the code, a number of things to remember:

- Overriding operator == is a feature of the C# language and there is no equivalent for it in the Intermediate Language (IL). In other words, the compiler replaces operator == with method calls to the operator overload’s static method.

- Any type that overloads operator == should also overload operator !=

- It only makes sense to override both Equals and GetHashCode methods when overloading operator ==.

- Just to put the record straight, if the GetHashCode of two objects of the same type return the same value, it does NOT mean they are equal!

- Also remember, if you are overloading operator ==, avoid using operator == in its implementation. You will probably get stock in an infinite recursion.

- ReferenceEquals and cast to object should be your friends to avoid recursion and calls to unwanted methods (i.e. You probably don’t want to call operator == overload from the Equals method when evaluating something like obj == null)

- You need to look after null values!

- Use the static Object.Equals method in operator == and != overloads to avoid needing to overload operator == for each inheritor of your class (The instance Equals method is virtual)

So here is an example:

class Rectangle

{

private readonly int _x;

private readonly int _y;

public Rectangle(int x, int y)

{

_x = x;

_y = y;

}

public override int GetHashCode()

{

return _x ^ _y;

}

public override bool Equals(object obj)

{

if (ReferenceEquals(obj, this))

return true;

Rectangle rect = obj as Rectangle;

// need to use ReferenceEquals or cast rect to object

// to avoid a call to the == operator overload below

if (ReferenceEquals(rect, null))

return false;

return rect._x == _x && rect._y == _y;

}

public static bool operator ==

(Rectangle r1, Rectangle r2)

{

// use Object.Equals to avoid needing to to provide == operator

// overload for all inheritors of this class

return Object.Equals(r1, r2);

}

public static bool operator !=

(Rectangle r1, Rectangle r2)

{

return !Object.Equals(r1, r2);

}

}