繁体   English   中英

.NET CIL Call或CallVirt?

[英].NET CIL Call or CallVirt?

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

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

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

  • 方法是static吗? 然后使用call
  • 是您在值类型上调用的类型? 然后使用call (如果值被装箱,则不适用 - 那么您实际上是在object或某个界面上调用,而这些是引用类型。)
  • 您调用的方法是virtual还是abstract 然后使用callvirt
  • 您是通过接口引用调用该方法吗? 然后使用callvirt
  • 您正在调用的方法是否声明override ,但方法和声明类型都没有声明sealed 然后使用callvirt

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

在非虚方法上使用callvirt等同于call除非第一个参数为null。 在这种情况下, callvirt会立即抛出NullReferenceException ,而call则不会。 这是有道理的,因为callvirt旨在用于需要虚拟方法调度的情况,如果没有可以进行vtable查找的对象,则无法进行虚拟方法调度。

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

考虑到这一信息,使用callvirt对引用类型的所有非静态方法调用(如C#编译器)可以是优选的,因为它会导致NullReferenceException ,立即在调用点,而不是一段时间后,当this被使用(明确或隐含)方法内部。

如果在虚方法的dynamic方法中使用call,则运行时会抛出安全异常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM