Overriding the equality operators
I’ve always found it rather painful to correctly override the equality operators in a class file. I always end up with cyclic references, stack overflows, null pointers, or other problems that are equally terrible. So finally today I sat down and figured out how to do it “correctly” – whereby “correctly” I mean, “in a way that gives me the right result without throwing an exception.
My model here is a very simple class called SimpleResponse. The class is generic (must be a primitive type, i.e. struct) and only has two fields: Value (of type T), and Description (of type String). Here’s how I did the equality overloads:
// Instance method
override public bool Equals(object obj) {
return Equals(this, obj as SimpleResponse<T>);
}
static public bool operator ==(SimpleResponse<T> first, SimpleResponse<T> second)
{
return Equals(first, second);
}
static public bool operator !=(SimpleResponse<T> first, SimpleResponse<T> second)
{
return !Equals(first, second);
}
static public bool Equals(SimpleResponse<T> first, SimpleResponse<T> second)
{
if (ReferenceEquals(first, null) && ReferenceEquals(second, null)) return true;
if (ReferenceEquals(first, null) || ReferenceEquals(second, null)) return false;
return Object.Equals(first.Value, second.Value) &&
String.Equals(first.Description, second.Description);
}
The important things to note here are:
- All the equality methods effectively just delegate to the Equals method right down the bottom.
- Since you’re overriding the == and != operators, you cannot use these in your Equals method to calculate equality – this will cause a StackOverflowException. This includes checking for null – note that you have to use ReferenceEquals instead (which is a static method on the Object class).
- Similarly, you can’t use the Equals method without causing a StackOverflowException. If you need to use an Equals method, you need to explicitly state which Object implements the method you want to use -note here I’m using String.Equals for comparing the descriptions, and Object.Equals when I can’t tell the type of the variable.
If anyone has suggestions as to a way I could have done this better, I’d love to hear them!
Doesn’t this kind of stuff make it more confusing for subsequent developers to maintain your code?
No, I don’t really think so – especially because I’m delegating all of the equality methods to the final one, so there’s only a single “point of failure”.