“这个”是什么意思?在 C# 中?

发布于 2024-11-28 03:24:37 字数 569 浏览 0 评论 0原文

在“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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

余生再见 2024-12-05 03:24:37

CLR 不会对非虚拟方法进行 null 检查。基本上,如果使用 call 指令调用方法,CLR 不会检查 null this 指针。相反,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 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/

╰ゝ天使的微笑 2024-12-05 03:24:37

this 指的是其自身(类)的当前实例。

您的代码片段

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

不起作用,因为您试图调用 null 的方法 GetFive,这是一个不存在的 Program 实例 - 在其他中换句话说,你正试图敲一扇虚空之门,一扇不存在的门。由于CLR不知道门的位置,因此它会抛出异常“找不到函数门!”对你来说 - 比未定义的行为好得多。

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.

ぃ弥猫深巷。 2024-12-05 03:24:37

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

也许该页面的重点是 IMPORTANT 部分,其中另一个 CLR 语言编译器生成一些使用您的 C# 类的代码,然后您将 C# 代码更改为非虚拟代码方法,而无需重新编译引用 C# 库的代码。在这种情况下,您可能会遇到问题,具体取决于调用者是实现 call 还是 callvirt(未定义编译器将执行的操作)。

c# 总是默认为 callvirt,所以没有问题,但对于调用者来说,你无法提前知道这一点。如果您这样做,则在传送库或 API 时可能会无意中破坏其他人的程序。


试试这个吧。

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

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(); 
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文