At page.170 of 'CLR via C#':
public sealed class Program {
public Int32 GetFive() { return 5; }
public static void Main() {
Program p = null;
Int32 x = p.GetFive(); // In C#, NullReferenceException is thrown
}
}
Theoretically, the code above is fine. Sure, the variable p is null, but when calling a nonvirtual method (GetFive), the CLR needs to know just the data type of p, which is Program. If GetFive did get called, the value of the this argument would be null. Since the argument is not used inside the GetFive method, no NullReferenceException would be thrown.
Pardon my stupid. I remember that CLR locate really method code by 'this' which always implictly appares at the first argument in method delcare, why it says 'when calling a nonvirtual method (GetFive), the CLR needs to know just the data type of p' ?
Okay. I just looked up pp. 170 of CLR via C#, 3rd edition.
Perhaps the whole point of the page is the IMPORTANT section whereby another CLR language compiler generates some code that uses your C# class, and then you change your C# code to a non virtual method without also recompiling the code referencing the C# library. In this case, you could have a problem depending on whether the caller implements call or callvirt (it is undefined what that compiler will do).
c# always defaults to callvirt, so no problem there, but for the caller you can't know this ahead of time. If you do this, you could unintentionally break somebody elses program if you are shipping libraries or APIs.
Try this instead.
The CLR doesn't do null checks for non-virtual methods. Basically, if a method is called with the
call
instruction, the CLR does not check for a nullthis
pointer. In contrast, thecallvirt
instruction always checks for nullity. However, C# emits thecallvirt
instruction whether or not the method is virtual.What the passage is saying is that if the C# compiler emitted the more semantically appropriate
call
instruction rather thancallvirt
instruction for non-virtual methods, then the code in question would not throw aNullReferenceException
. As I recall, the compiler team decided to almost always emit thecallvirt
instruction because it handled versioning better (also the JIT can optimize acallvirt
into acall
).See http://www.pvle.be/tag/clr/
this
refers to the current instance of itself (the class).Your code snippet,
does not work because you are trying to call a method
GetFive
ofnull
, a non-existent instance ofProgram
- in other words, you are trying to knock on a door of a void, a door that does not exist. Since the CLR doesn't know the location of the door, it throws an exception "cannot find function door!" for you - much better than undefined behaviour.