It looks like the issue is that when MS introduced nullable types, they made it so that every struct is implicitly convertable to its nullable type (foo?
), so the code
if( f == null)
is equivalent to
if ( (Nullable<foo>)f == (Nullable<foo>)null)
Since MSDN states that "any user-defined operators that exist for value types may also be used by nullable types", when you override operator==
, you allow that implicit cast to compile, as you now have a user-defined == -- giving you the nullable overload for free.
An aside:
Seems like in your example, there is some compiler optimization
The only thing that is emitted by the compiler that even hints there was a test is this IL:
ldc.i4.0
ldc.i4.0
ceq
stloc.1 //where there is an unused boolean local
Note that if you change main to
Foo f = new Foo();
object b = null;
if (f == b) { Console.WriteLine("?"); }
It no longer compiles. But if you box the struct:
Foo f = new Foo();
object b = null;
if ((object)f == b) { Console.WriteLine("?"); }
if compiles, emits IL, and runs as expected (the struct is never null);