C# · 12月 24, 2021

c# – .NET CIL Call或CallVirt?

如何确定是否需要使用“Call”或“Callvirt”调用方法?解决方法 您可以逐个遵循这些简单的规则来确定您应该使用哪些:

>方法是静态的吗?然后使用电话.
>您在值类型上调用的类型是什么?然后使用电话. (如果值被装箱,则不适用 – 那么您实际上是在对象或某个界面上调用,而这些是引用类型.)
>您调用的方法是虚拟还是抽象?然后使用callvirt.
>您是通过接口引用调用该方法吗?然后使用callvirt.
>您调用的方法是否声明覆盖,但方法和声明类型都没有声明密封?然后使用callvirt.

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

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

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

考虑到这些信息,对引用类型的所有非静态方法调用使用callvirt(如C#编译器所做的那样)可能更好,因为它会在调用站点立即导致NullReferenceException,而不是在以后使用它时(显式或隐式)方法内部.