There are three virtual methods that IMHO should have never been added to System.Object…
• ToString()
• GetHashCode()
• Equals()
All of these could have been implemented as an interface. Had they done so I think we’d be much better off. So why are these a problem?

First let’s focus on ToString():
1. If ToString() is expected to be implemented by someone using ToString() and displaying the results you have an implicit contract that the compiler cannot enforce. Your code might assume that ToString() is overloaded, but there is no way to force that to be the case. Had this been an interface, say IDisplayString, your client code would be able to ensure that an object implement this.

2. Most argue the benefit of overloading ToString() is for the debugger. You should NOT be doing this, instead you should start using [System.Diagnostics.DebuggerDisplayAttribute].

3. As for needing this implementation for converting objects to strings via String.Format(), and/or Console.WriteLine, they could have deferred to the System.Convert.ToString(object) and checked for something like ‘IDisplayString’, failing over to the type’s name if not implemented.

4. Exactly what ToString() returns or should return seems to be a matter of debate and is the worst of all it’s problems. Is this a display string? If so, for what culture? Is this a serialization string? Is it just for debugging? There doesn’t seem to be any correct answer.

And don’t even get me started on GetHashCode/Equals.
1. Overloading .Equals has nothing to do with expressing equality in your code (value1 == value2) unless you remember to call it directly. Stupid!

2. There are numerous ways in which to compare two objects. Reference comparison is one, or perhaps by an object’s identity field, or even a name field? What I love most is that the reference comparison is difficult to produce on an object that overloads these. Does anyone know how to get the ‘hash’ of an object’s reference (memory location)? BTW you can, it’s not in an obvious place like Object.GetHash(object), it’s RuntimeHelpers.GetHashCode(object).

3. Casting — why lord, why? Why must you make me cast the object I’m comparing myself to. And what do I do with null or some other object type? Is there some standard I’ve never heard of that defines the appropriate action? Certainly neither equality or inequality are the correct response?

4. What comparison will be used? I’ve implemented IEquatable before, sometimes things I call even use it; however, a larger part of the time I still have to overload the object’s GetHashCode/Equals.

5. Much like ToString() there isn’t a way to tell if an object actually implements this behavior. If it does, did I want them to is an entirely different story. They could be breaking my code by implementing these without either of us knowing I was depending upon reference comparison.

So I say enough already, can we please just deprecate these already? I’d even be willing to find and fix all the places I’ve been unwillingly forced to use these damn things.

Comments