.NET CIL Call或CallVirt?

时间:2010-11-17 23:41:41

标签: c# .net cil .net-3.5

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

3 个答案:

答案 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,则运行时会抛出安全异常。