.NET CIL 调用还是 CallVirt?
如何确定一个方法是否需要使用“Call”或“Callvirt”来调用?
How can I determine if a method needs to be called with "Call" or "Callvirt"?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以一一遵循这些简单的规则来确定应该使用哪一个:
静态
吗?然后使用调用
。调用
。 (如果值被装箱,则此不适用 - 那么您实际上是在对象
或某些接口上调用,并且这些是引用类型。)虚拟
还是抽象
?然后使用callvirt。override
,但该方法和声明类型均未声明sealed
?然后使用callvirt。在所有其他情况下,不需要虚拟调度,因此您可以使用
call
- 但您应该使用callvirt
。原因如下:在非虚拟方法上使用
callvirt
与call
等效,除非第一个参数为 null。在这种情况下,callvirt
将立即抛出NullReferenceException
,而call
则不会。这是有道理的,因为callvirt
旨在用于需要虚拟方法分派的情况,并且如果没有要执行 vtable 的对象,则无法执行虚拟方法分派抬头。请注意,如果第一个参数为 null,即使不需要 vtable 查找,
callvirt
仍然会抛出异常!考虑到此信息,对引用类型的所有非静态方法调用(如 C# 编译器所做的那样)使用 callvirt 可能更可取,因为它将在调用时立即导致 NullReferenceException站点,而不是稍后在方法内部(显式或隐式)使用
this
时。You can follow these simple rules one by one to determine which you should use:
static
? Then usecall
.call
. (This does not apply if the value is boxed -- then you are actually invoking onobject
or some interface, and those are reference types.)virtual
orabstract
? Then usecallvirt
.callvirt
.override
, but neither the method nor the declaring type declaredsealed
? Then usecallvirt
.In all other cases, no virtual dispatch is required so you can use
call
-- but you should usecallvirt
. Here's why:Using
callvirt
on non-virtual methods is equivalent tocall
except when the first argument is null. In that casecallvirt
will throw aNullReferenceException
immediately, whereascall
will not. This makes sense, becausecallvirt
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.Note that
callvirt
will still throw an exception if the first argument is null even if a vtable lookup isn't necessary!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 aNullReferenceException
immediately at the call site instead of sometime later whenthis
gets used (explicitly or implicitly) inside of the method.默认情况下,C# 编译器始终使用 callvirt 执行除静态或值类型调用之外的所有操作。这会导致对“this”(arg0)参数进行隐式空检查。并不严格要求您遵循此约定,但引用类型上的任何虚拟方法肯定需要 callvirt。
By default, the C# compiler always uses callvirt for everything except static or value type calls. This causes implicit null checking of the 'this' (arg0) argument. You're not strictly required to follow this convention, but any virtual method on a reference type will definitely require callvirt.
如果您在虚拟方法上使用动态方法调用,则运行时会引发安全异常。
If you use call in a dynamicmethod on a virtual method the runtime throws a security exception.