What's the meaning of 'this' in C#?

2019-07-29 23:07发布

问题:

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' ?

回答1:

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 null this pointer. In contrast, the callvirt instruction always checks for nullity. However, C# emits the callvirt 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 than callvirt instruction for non-virtual methods, then the code in question would not throw a NullReferenceException. As I recall, the compiler team decided to almost always emit the callvirt instruction because it handled versioning better (also the JIT can optimize a callvirt into a call).

See http://www.pvle.be/tag/clr/



回答2:

this refers to the current instance of itself (the class).

Your code snippet,

Program p = null;
Int32 x = p.GetFive(); // In C#, NullReferenceException is thrown

does not work because you are trying to call a method GetFive of null, a non-existent instance of Program - 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.



回答3:

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.

    public static Int32 GetFive() { return 5; }    
    public static void Main() {       
        Int32 x = GetFive(); 
    }


标签: c# clr