I assume you were considering implementing .NET 3.5? I find the implementation of .NET 4 is a little different.
However, I have a suspicious suspicion that this is due to the fact that you can even call virtual instance methods with virtually no null reference. Perhaps in IL, that is. I will see if I can create an IL that will call null.Equals(null) .
EDIT: Ok, here is some interesting code:
.method private hidebysig static void Main() cil managed { .entrypoint
I got this by compiling the following C # code:
using System; class Test { static void Main() { string x = null; Console.WriteLine(x.Equals(null)); } }
... and then disassembling using ildasm and editing. Pay attention to this line:
IL_0005: call instance bool [mscorlib]System.String::Equals(string)
Originally it was callvirt instead of call .
So what happens when we collect it? Well, with .NET 4.0 we get the following:
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object. at Test.Main()
Hm. What's with .NET 2.0?
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object. at System.String.EqualsHelper(String strA, String strB) at Test.Main()
Now, more interestingly ... we obviously managed to get into EqualsHelper , which we usually did not expect.
Enough of the line ... try to implement referential equality yourself and see if we can get null.Equals(null) to return true:
using System; class Test { static void Main() { Test x = null; Console.WriteLine(x.Equals(null)); } public override int GetHashCode() { return base.GetHashCode(); } public override bool Equals(object other) { return other == this; } }
The same procedures as before - to parse, change callvirt to call , collect and see its print true ...
Note that while the other answers this question in C ++ , we are even more insidious here ... because we invoke the virtual method in practice. Usually even a C ++ / CLI compiler will use callvirt for a virtual method. In other words, I think that in this particular case, the only way for this be null is to manually write IL.
EDIT: I just noticed something ... In fact, I did not name the correct method in any of our small sample programs. Here's the call in the first case:
IL_0005: call instance bool [mscorlib]System.String::Equals(string)
here is the call in the second:
IL_0005: call instance bool [mscorlib]System.Object::Equals(object)
In the first case, I called System.String::Equals(object) , and in the second I called Test::Equals(object) . From this we can see three things:
- You need to be careful with overload.
- The C # compiler emits calls to the virtual method declarator - not the most concrete redefinition of the virtual method. IIRC, VB works in reverse.
object.Equals(object) glad to compare the null reference "this"
If you add a little console output to the C # override, you will see the difference - it will not be called unless you change the IL to call it explicitly, for example:
IL_0005: call instance bool Test::Equals(object)
So here we are. Fun and abuse of instance methods on null links.
If you have done this this far, you might also like my blog post about how value types can be declared by constructors without parameters ... in IL.