.NET CIL 调用还是 CallVirt?

发布于 2024-10-03 05:32:15 字数 42 浏览 0 评论 0原文

如何确定一个方法是否需要使用“Call”或“Callvirt”来调用?

How can I determine if a method needs to be called with "Call" or "Callvirt"?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(3

泪意 2024-10-10 05:32:15

您可以一一遵循这些简单的规则来确定应该使用哪一个:

  • 该方法是静态吗?然后使用调用
  • 您调用的类型是值类型吗?然后使用调用。 (如果值被装箱,则此适用 - 那么您实际上是在对象或某些接口上调用,并且这些是引用类型。)
  • 是您正在调用的方法声明虚拟还是抽象?然后使用callvirt。
  • 您是否通过接口引用调用该方法?然后使用callvirt。
  • 您正在调用的方法是否已声明override,但该方法和声明类型均未声明sealed?然后使用callvirt。

在所有其他情况下,不需要虚拟调度,因此您可以使用call - 但您应该使用callvirt 。原因如下:

在非虚拟方法上使用 callvirtcall 等效,除非第一个参数为 null。在这种情况下,callvirt 将立即抛出 NullReferenceException,而 call 则不会。这是有道理的,因为 callvirt 旨在用于需要虚拟方法分派的情况,并且如果没有要执行 vtable 的对象,则无法执行虚拟方法分派抬头。

请注意,如果第一个参数为 null,即使不需要 vtable 查找,callvirt 仍然会抛出异常!

考虑到此信息,对引用类型的所有非静态方法调用(如 C# 编译器所做的那样)使用 callvirt 可能更可取,因为它将在调用时立即导致 NullReferenceException站点,而不是稍后在方法内部(显式或隐式)使用 this 时。

You can follow these simple rules one by one to determine which you should use:

  • Is the method static? Then use call.
  • Is the type you are invoking on a value type? Then use call. (This does not apply if the value is boxed -- then you are actually invoking on object or some interface, and those are reference types.)
  • Is the method you are invoking declared virtual or abstract? Then use callvirt.
  • Are you invoking the method through an interface reference? Then use callvirt.
  • Is the method you are invoking declared override, but neither the method nor the declaring type declared sealed? Then use callvirt.

In all other cases, no virtual dispatch is required so you can use call -- but you should use callvirt. Here's why:

Using callvirt on non-virtual methods is equivalent to call except when the first argument is null. In that case callvirt will throw a NullReferenceException immediately, whereas call will not. This makes sense, because callvirt is intended to be used in cases where virtual method dispatch is desired, and you can't do virtual method dispatch if you don't have an object on which to do a vtable lookup.

Note that callvirt will still throw an exception if the first argument is null even if a vtable lookup isn't necessary!

Considering this information, using callvirt for all non-static method invocations on reference types (as the C# compiler does) may be preferable as it will cause a NullReferenceException immediately at the call site instead of sometime later when this gets used (explicitly or implicitly) inside of the method.

萧瑟寒风 2024-10-10 05:32:15

默认情况下,C# 编译器始终使用 callvirt 执行除静态或值类型调用之外的所有操作。这会导致对“this”(arg0)参数进行隐式空检查。并不严格要求您遵循此约定,但引用类型上的任何虚拟方法肯定需要 callvirt。

By default, the C# compiler always uses callvirt for everything except static or value type calls. This causes implicit null checking of the 'this' (arg0) argument. You're not strictly required to follow this convention, but any virtual method on a reference type will definitely require callvirt.

独自唱情﹋歌 2024-10-10 05:32:15

如果您在虚拟方法上使用动态方法调用,则运行时会引发安全异常。

If you use call in a dynamicmethod on a virtual method the runtime throws a security exception.

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