Using Reflector or DotPeek, the System.Linq.Data.Binary implementation of the equality operator overload looks like this:
[Serializable, DataContract]
public sealed class Binary : IEquatable<Binary>
{
...
public static bool operator ==(Binary binary1, Binary binary2)
{
return ((binary1 == binary2) || (((binary1 == null) && (binary2 == null)) || (((binary1 != null) && (binary2 != null)) && binary1.EqualsTo(binary2))));
}
I must be missing something obvious, or there is a mechanism taking place of which I’m unaware (such as implicitly calling object == within the body?). I admit, I rarely if ever need to overload standard operators.
Why does this implementation not result in an infinite recursion (which a simple test shows it doesn’t recurse infinitely)? The first conditional expression is binary1 == binary2, within the implementation of the operator overload that would get called if you used binary1 == binary2 outside the implementation, and I would have thought, inside as well.
I expect this to be a bug in your decompiler. Redgate Reflector had/has the same bug, and I’ve found it in ILSpy too.
The reason why this is hard to decompile is because it subtly tests the C# overloading rules. The original code was most likely something like
(object)obj1==(object)obj2, but this conversion can’t be seen in the IL itself. Casting any reference type to a base type is a no-op as far as the runtime is concerned. It does however get C# to choose the referential equality opcodes instead of calling the overloaded equality operators.IMO the correct way to implement this in a decompiler is to always decompile referential equality checks to
(object)obj1==(object)obj2and then optimize out the redundant casts if they don’t affect overload resolution. This approach will fix similar problems with method overloading too.