如何确定是否需要使用“Call”或“Callvirt”调用方法?
答案 0 :(得分:6)
默认情况下,C#编译器始终将callvirt用于除静态或值类型调用之外的所有内容。这会导致对'this'(arg0)参数进行隐式空值检查。您并不是严格要求遵循此约定,但引用类型上的任何虚拟方法肯定都需要callvirt。
答案 1 :(得分:4)
您可以逐个遵循这些简单规则来确定您应该使用哪些:
static
吗?然后使用call
。call
。 (如果值已装箱,则此不适用 - 那么您实际上是在object
或某个界面上调用,而这些是参考类型。)virtual
还是abstract
?然后使用callvirt
。callvirt
。override
,但方法和声明类型都没有声明sealed
?然后使用callvirt
。在所有其他情况下,不需要虚拟调度,因此可以使用call
- 但应该使用callvirt
。原因如下:
在非虚拟方法上使用callvirt
等同于call
,除非第一个参数为null。在这种情况下,callvirt
会立即抛出NullReferenceException
,而call
则不会。这是有道理的,因为callvirt
旨在用于需要虚拟方法调度的情况,如果没有可以进行vtable查找的对象,则无法进行虚拟方法调度。< / p>
请注意,即使不需要vtable查找,如果第一个参数为null,callvirt
仍会抛出异常!
考虑到这些信息,使用callvirt
对引用类型的所有非静态方法调用(如C#编译器那样)可能更好,因为它会立即在调用站点导致NullReferenceException
而不是稍后在this
内部(显式或隐式)使用方法时。
答案 2 :(得分:0)
如果在虚方法的dynamic方法中使用call,则运行时会抛出安全异常。