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

最佳答案

您可以按照这些简单的规则逐一确定应该使用哪些规则:
方法是否static?然后使用call
是在值类型上调用的类型吗?然后使用call。(如果值是装箱的,则不适用于此项——然后您实际上是在object或某些接口上调用,而这些接口是引用类型。)
您调用的方法是否声明为virtualabstract?然后使用callvirt
是否通过接口引用调用方法?然后使用callvirt
您正在调用的方法是否声明为override,但该方法和声明类型都未声明为sealed?然后使用callvirt
在所有其他情况下,不需要虚拟分派,因此您可以使用call——但您应该使用callvirt。原因如下:
对非虚方法使用callvirt等同于call,除非第一个参数为空。在这种情况下,callvirt会立即抛出一个NullReferenceException,而call不会。这是有意义的,因为callvirt用于需要虚拟方法分派的情况,并且如果没有要对其执行vtable查找的对象,则无法执行虚拟方法分派。
注意,如果第一个参数为空,即使不需要vtable查找,callvirt仍会抛出异常!
考虑到这一信息,对于引用类型上的所有非静态方法调用使用callvirt可能是可取的(正如c编译器所做的那样),因为它将在调用站点立即导致NullReferenceException,而不是稍后在方法内部(显式或隐式)使用this时。

07-28 03:14