You can follow these simple rules one by one to determine what you should use:
- Is the method
static ? Then use call . - Is the type you are calling for the type of value used? Then use
call . (This does not apply if the value is inserted into the box - then you are actually calling on object or some interface, and these are reference types.) - Is the method you call declared
virtual or abstract ? Then use callvirt . - Are you calling a method through a link to an interface? Then use
callvirt . - Is the method called that you call the declared
override called, but neither the method nor the declared type are declared sealed ? Then use callvirt .
In all other cases, virtual sending is not required, so you can use call - but you must use callvirt . That's why:
Using callvirt for non-virtual methods is equivalent to call , unless the first argument is null. In this case, callvirt immediately throw a NullReferenceException , while call will not. This makes sense, since callvirt designed to be used in cases where you need to send a virtual method, and you cannot send a virtual method if you do not have an object for which you can search in vtable.
Note that callvirt will still throw an exception if the first argument is zero, even if vtable search is not needed!
Given this information, using callvirt for all non-static method calls in reference types (as the C # compiler does) may be preferable, as this will cause an immediate NullReferenceException to be NullReferenceException at the call site, and not sometime later when this used ( explicitly or implicitly) inside a method.
cdhowie
source share