How can I determine if a method needs to be called with "Call" or "Callvirt"?
You can follow these simple rules one by one to determine which you should use:
static
? 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.)virtual
or abstract
? Then use callvirt
.callvirt
.override
, but neither the method nor the declaring type declared sealed
? Then use callvirt
.In all other cases, no virtual dispatch is required so you can use call
-- but you should use callvirt
. Here's why:
Using callvirt
on non-virtual methods is equivalent to call
except when the first argument is null. In that case callvirt
will throw a NullReferenceException
immediately, whereas call
will not. 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.
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 a NullReferenceException
immediately at the call site instead of sometime later when this
gets used (explicitly or implicitly) inside of the method.
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 love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With