2011-08-03 93 views
1

在 '通过C#CLR' 的page.170:C#中'this'的含义是什么?


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 
    } 
} 

理论上,上面的代码是好的。当然,变量p为null,但在调用非虚拟方法(GetFive)时,CLR需要知道p的数据类型,即Program。如果 GetFive确实被调用,则此参数的值将为null。由于在GetFive方法中没有使用参数 ,因此不会引发NullReferenceException。


请原谅我的愚蠢。我记得CLR通过'this'找到了真正的方法代码,它总是暗示着方法delcare中的第一个参数,为什么它说'调用非虚拟方法(GetFive)时,CLR需要知道p'的数据类型?

+2

Ummmm什么????? –

+1

但“GetFive”是一种实例方法,不是静态方法。即使您没有在“GetFive”方法中使用任何实例变量,运行时仍然需要知道该方法正在执行的对象实例。 – feathj

+0

@Kirk Woll我认为这段文字是 – saus

回答

5

CLR不会对非虚拟方法执行空检查。基本上,如果使用call指令调用方法,则CLR不会检查空指针this。相反,callvirt指令总是检查无效。但是,无论该方法是否为虚拟,C#都会发出callvirt指令。

什么通道的意思是,如果C#编译器发出的语义上更合适call指令,而不是callvirt指令非虚方法,那么有问题的代码不会抛出NullReferenceException。我记得,编译器团队决定几乎总是发出callvirt指令,因为它更好地处理了版本控制(也是JIT可以将callvirt优化为call)。

参见http://www.pvle.be/tag/clr/

+1

这本书的引用“编译器团队决定几乎总是发出callvirt指令,因为它更好地处理了版本控制” - 主要原因是C#需要在调用方法时抛出NullReferenceExceptions一个空引用。最简单的方法是使用'callvirt'(它检查它的参数)而不是'call'。 – porges

+1

尽管我也相信陈述的理由是错误的,但C#编译器对类的所有实例方法调用使用'callvirt'是为什么在这里抛出'NullReferenceException'的正确原因。 –

+0

你所引用的文章对我来说非常有用。非常感谢! –

3

this指本身(类)当前实例。

您的代码段,

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

不工作,因为你正在试图调用GetFivenull的方法中,Program一个不存在的实例 - 换句话说,你正在试图敲门一个空洞,一扇不存在的门。由于CLR不知道门的位置,它会抛出一个异常“找不到功能门!”对你来说 - 比未定义的行为好得多。

+0

我认为OP意识到为什么在c#中抛出nullreferenceexception,但他的问题是“为什么从'CLR'通过C#'这段话说CLR不检查非虚方法的空值”...编辑:但然后再次,看着问题的标题,我不太确定问题是什么...... – saus

0

好的。我刚刚通过C#第3版查阅了CLR的第170页。

也许首页的整个点是重要部分,其中另一CLR语言编译器生成一个使用C#类的一些代码,然后你改变你的C#代码到一个非虚方法不还重新编译代码引用C#库。在这种情况下,可能会根据调用者是调用callvirt还是callvirt(它不确定编译器会做什么)而产生问题。

C#总是默认为callvirt,所以有没有问题,但对来电者不能提前知道这一点。如果你这样做,如果你运送图书馆或API,你可能会无意间破坏某人的程序。


试试这个。

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