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);
}
}