简体   繁体   English

.NET CIL Call或CallVirt?

[英].NET CIL Call or CallVirt?

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

By default, the C# compiler always uses callvirt for everything except static or value type calls. 默认情况下,C#编译器始终将callvirt用于除静态或值类型调用之外的所有内容。 This causes implicit null checking of the 'this' (arg0) argument. 这会导致对'this'(arg0)参数进行隐式空值检查。 You're not strictly required to follow this convention, but any virtual method on a reference type will definitely require callvirt. 您并不是严格要求遵循此约定,但引用类型上的任何虚拟方法肯定都需要callvirt。

You can follow these simple rules one by one to determine which you should use: 您可以逐个遵循这些简单的规则来确定您应该使用哪些:

  • Is the method static ? 方法是static吗? Then use call . 然后使用call
  • Is the type you are invoking on a value type? 是您在值类型上调用的类型? Then use call . 然后使用call (This does not apply if the value is boxed -- then you are actually invoking on object or some interface, and those are reference types.) (如果值被装箱,则不适用 - 那么您实际上是在object或某个界面上调用,而这些是引用类型。)
  • Is the method you are invoking declared virtual or abstract ? 您调用的方法是virtual还是abstract Then use callvirt . 然后使用callvirt
  • Are you invoking the method through an interface reference? 您是通过接口引用调用该方法吗? Then use callvirt . 然后使用callvirt
  • Is the method you are invoking declared override , but neither the method nor the declaring type declared sealed ? 您正在调用的方法是否声明override ,但方法和声明类型都没有声明sealed Then use callvirt . 然后使用callvirt

In all other cases, no virtual dispatch is required so you can use call -- but you should use callvirt . 在所有其他情况下,不需要虚拟调度,因此您可以使用call - 但您应该使用callvirt Here's why: 原因如下:

Using callvirt on non-virtual methods is equivalent to call except when the first argument is null. 在非虚方法上使用callvirt等同于call除非第一个参数为null。 In that case callvirt will throw a NullReferenceException immediately, whereas call will not. 在这种情况下, callvirt会立即抛出NullReferenceException ,而call则不会。 This makes sense, because callvirt is intended to be used in cases where virtual method dispatch is desired, and you can't do virtual method dispatch if you don't have an object on which to do a vtable lookup. 这是有道理的,因为callvirt旨在用于需要虚拟方法调度的情况,如果没有可以进行vtable查找的对象,则无法进行虚拟方法调度。

Note that callvirt will still throw an exception if the first argument is null even if a vtable lookup isn't necessary! 请注意,即使不需要vtable查找,如果第一个参数为null, callvirt仍将抛出异常!

Considering this information, using callvirt for all non-static method invocations on reference types (as the C# compiler does) may be preferable as it will cause a NullReferenceException immediately at the call site instead of sometime later when this gets used (explicitly or implicitly) inside of the method. 考虑到这一信息,使用callvirt对引用类型的所有非静态方法调用(如C#编译器)可以是优选的,因为它会导致NullReferenceException ,立即在调用点,而不是一段时间后,当this被使用(明确或隐含)方法内部。

如果在虚方法的dynamic方法中使用call,则运行时会抛出安全异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM