I have been reading a chapter on C# canonical forms in “Accelerated C# 2008” by Trey Nash when I came across a piece of code that puzzled me. The book is an excellent resource on the language and I can recommend it to everyone, even the more seasoned C# developers.

So, the code I am referring to is on overriding Object.Equals method for reference types. You can find it in chapter 13 on page 386 of the 2nd edition. I am not allowed to reproduce the whole program here, but I will highlight the lines of code that confused me. The code is an example of how to override Object.Equals for a reference type variable when you need the value type semantics. The author provides the override with the following signature:

public override bool Equals(object obj)

In addition, the example has a static definition for == operator. The passed parameters are of the class type the method is defined in:

public  static bool operator==(ComplexNumber me, ComplexNumber other)
    return Equals(me, other);

In the Main, two instanced of the ComplexNumber class are declared, both, with the same argument values. The test for equality is the invoked as:

System.Console.WriteLine("Results of Equality is {0}", referenceA == referenceB);

Ok, the above line of code will call the static method operator==, which in turn calls Equals(me,other). So, who calls Equals(object obj)? As I was reading this, I said to myself that there was no way this would compile as there is clearly a mistake in the number of parameters in the Equals call inside operator==. This bothered me since all other code examples in the book were ‘compileable’, at least in my head. So, I went to my desktop PC and typed-up the example, fully expecting it to fail. But it did not. It compiled and ran as expected. I added debug points to see which method is called after Equals(me, other). To my surprise – the Equals(object obj) was called! But it did not make any sense at all…

I was beginning to suspect some ‘implicit substitution’ with this voodoo magic, when I decided to look at the trusty IL in ILDASM. This is what I saw for op_Equality:

Figure 1

Aha! I am not crazy, because clearly the call is to Equals(object,object), not to Equals(object). So, how does a call to Equals(object,object) resolves to a call to Equals(object)? How?!

I was able to find the answer on the MSDN website. Object.Equals(Object,Object) is a static method, so, it cannot be overridden. The answer to my puzzle lies in the Remarks section, where we find this line:

  • If the two objects do not represent the same object reference and neither is null, it calls objA.Equals(objB) and returns the result. This means that if objA overrides the Object.Equals(Object) method, this override is called.

This is what was going on!