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