“这个”是什么意思?在 C# 中?
在“CLR via C#”的第170页:
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 确实被调用,this 参数的值将为 null。自从争论以来 未在 GetFive 方法内部使用,不会抛出 NullReferenceException。
原谅我的愚蠢。我记得CLR通过“this”来定位真正的方法代码,它总是隐式地出现在方法delcare的第一个参数处,为什么它说“当调用非虚拟函数时” 方法 (GetFive) 时,CLR 只需要知道 p' 的数据类型?
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' ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
CLR 不会对非虚拟方法进行 null 检查。基本上,如果使用
call
指令调用方法,CLR 不会检查 nullthis
指针。相反,callvirt
指令始终检查是否无效。但是,无论该方法是否为虚拟方法,C# 都会发出callvirt
指令。这段话的意思是,如果 C# 编译器为非虚拟方法发出语义上更合适的
call
指令,而不是callvirt
指令,那么相关代码就不会抛出异常NullReferenceException 。我记得,编译器团队决定几乎总是发出callvirt
指令,因为它可以更好地处理版本控制(而且 JIT 可以将callvirt
优化为call
代码>)。请参阅http://www.pvle.be/tag/clr/
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
指的是其自身(类)的当前实例。您的代码片段
不起作用,因为您试图调用
null
的方法GetFive
,这是一个不存在的Program
实例 - 在其他中换句话说,你正试图敲一扇虚空之门,一扇不存在的门。由于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.好的。我刚刚查阅了 CLR via C#,第 3 版的第 170 页。
也许该页面的重点是 IMPORTANT 部分,其中另一个 CLR 语言编译器生成一些使用您的 C# 类的代码,然后您将 C# 代码更改为非虚拟代码方法,而无需重新编译引用 C# 库的代码。在这种情况下,您可能会遇到问题,具体取决于调用者是实现 call 还是 callvirt(未定义编译器将执行的操作)。
c# 总是默认为 callvirt,所以没有问题,但对于调用者来说,你无法提前知道这一点。如果您这样做,则在传送库或 API 时可能会无意中破坏其他人的程序。
试试这个吧。
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.