你可以一一遵循这些简单的规则来决定你应该使用哪一个:
static?然后使用call.call. (如果该值被装箱,则这不适用——那么您实际上是在调用object某个接口,而这些是引用类型。)virtual还是abstract?然后使用callvirt.callvirt.override,但方法和声明类型均未声明sealed?然后使用callvirt.在所有其他情况下,不需要虚拟分派,因此您可以使用call- 但您应该使用callvirt. 原因如下:
使用callvirt在非虚拟方法相当于call除了当第一参数为空。在那种情况下callvirt会NullReferenceException立即抛出一个,而call不会。这是有道理的,因为callvirt它旨在用于需要虚拟方法分派的情况,如果您没有可以在其上进行 vtable 查找的对象,则无法进行虚拟方法分派。
请注意,callvirt即使不需要 vtable 查找,如果第一个参数为空,它仍然会抛出异常!
考虑到此信息,callvirt对引用类型的所有非静态方法调用(如 C# 编译器所做的那样)可能更可取,因为它会NullReferenceException立即在调用站点而不是稍后在this内部使用(显式或隐式)方法。
默认情况下,C#编译器始终将callvirt用于除静态或值类型调用之外的所有内容.这会导致对'this'(arg0)参数进行隐式空值检查.您并不是严格要求遵循此约定,但引用类型上的任何虚拟方法肯定都需要callvirt.