Jelle Druyts .NET Consultant
Just another ignorant weirdo from Antwerp, Belgium trying to make sense out of it all
BradA poses an interesting question in his post on NullReferenceExceptions: "What if you have an instance method that does not touch any instance state (for example an instance method that just does a Console.WriteLine (“hello“)). Will you get a NullReferenceException when you call that?".
Off the top of my hat, I'd say it should be possible from the CLR perspective to call instance methods on null objects. As Brad says: a NullReferenceException occurs when you access instance state, i.e. when you use the implicit this reference that is passed in every instance method. If your method never uses that reference, I'd say you have no problem.
null
this
So I just tried that and it doesn't seem to work though (as I could have expected but still). Imagine a TestClass with a DoTest method that just writes a line to the console. If you look at the IL the C# compiler built for us, it says:
.locals (TestClass V_0) L_0000: ldnull L_0001: stloc.0 L_0002: ldloc.0 L_0003: callvirt TestClass.DoTest
As you see it just calls a method, the null reference is on the stack ready to be used as the this parameter, but it won't be used by the method call. So I'd say: rock on. But the runtime says: curtains close. Maybe it has something to do with the fact that the C# compiler always emits a virtual call (callvirt) even though I made TestClass sealed. And then it goes off looking for the object header to find the pointers to the baseclass or something, failing because there's no object header since there's no instance? I don't know, I'd have to dig deeper into the internals to find out but I think I'm on the right track here...
By the way, I've always loved the name "NullReferenceException" in sharp contrast to Java's "NullPointerException". Made me chuckle when I first saw that
Update: as BradA pointed out in my comments, I seemed to be on the right track indeed. So I took his advice and changed the "callvirt" into a regular "call" and - lo and behold - it works! (So I'm asking "nobody" to do something for me and got away with it. I should try this for my dishes...)
A quick peek at Don Box's excellent Essential .NET Volume 1 (page 158-159) tells me why: a non-virtual call is just a jump to the exact place in memory where the JIT compiler placed the native code. No magic required. A virtual call however (which the C# compiler always creates, and I think somewhere in that book Don explains why that is - although I can't seem to remember right now...) will use the object's RuntimeTypeHandle to determine the proper method to call. Well, a RuntimeTypeHandle is instance state - which won't work on null objects. And so it fails. Yep, that about feels right...
RuntimeTypeHandle
Update: I won - woohoo Thanks for the 2 .NET t-shirts and the note, Brad. Although I must say, I was really hoping for a job offer