Comment puis-je déterminer si une méthode doit être appelée avec "Call" ou "Callvirt"?.NET CIL Appel ou CallVirt?
Répondre
Vous pouvez suivre ces règles simples, un par un pour déterminer lequel vous devez utiliser:
- est la méthode
static
? Ensuite, utilisezcall
. - Le type que vous appelez sur un type de valeur? Ensuite, utilisez
call
. (Ce n'a pas si sa valeur est encadrée - alors vous invoquez en fait surobject
ou une interface, et ce sont les types de référence.) - est la méthode que vous invoquez
virtual
ouabstract
déclarée? Ensuite, utilisezcallvirt
. - Appelez-vous la méthode via une référence d'interface? Ensuite, utilisez
callvirt
. - La méthode que vous appelez a-t-elle été déclarée
override
, mais ni la méthode ni le type de déclaration n'ont été déclaréssealed
? Ensuite, utilisezcallvirt
.
Dans tous les autres cas, aucune expédition virtuelle est requise pour que vous pouvez utilisercall
- mais vous devriez utiliser callvirt
. Voici pourquoi:
L'utilisation de callvirt
sur des méthodes non virtuelles est équivalente à call
sauf lorsque le premier argument est null. Dans ce cas callvirt
va lancer un NullReferenceException
immédiatement, alors que call
ne sera pas. Cela est logique, car callvirt
est destiné à être utilisé dans les cas où l'envoi de méthode virtuelle est souhaité, et vous ne pouvez pas faire de répartition de méthode virtuelle si vous n'avez pas un objet sur lequel effectuer une recherche vtable.
Notez que callvirt
lèvera quand même une exception si le premier argument est null même si une recherche de vtable n'est pas nécessaire!
Compte tenu de ces informations, en utilisant callvirt
pour toutes les invocations de méthode non statique sur les types de référence (comme le compilateur C# ne) peut être préférable, car cela fera un NullReferenceException
immédiatement sur le site d'appel au lieu de quelque temps plus tard, quand this
s'accoutume (explicitement ou implicitement) à l'intérieur de la méthode.
Mais .NET utilise "call" pour appeler quelque chose comme Point.X. De ce que je lis apparemment méthodes de type de valeur utilisent "appel". – Will
Oui, parce que ces méthodes ne sont pas virtuelles, donc je m'attendrais à ce que la sortie utilise "call". Lisez ma réponse à nouveau. (De plus, les structures * ne peuvent pas * avoir de membres virtuels puisqu'elles ne peuvent pas être héritées.) – cdhowie
Cela a du sens, merci. Juste bizarre que la réflexion montre "IsVirtual" comme vrai pour les méthodes de struct. – Will
Par défaut, le compilateur C# utilise toujours callvirt pour tout sauf les appels statiques ou de type valeur. Cela provoque une vérification nulle implicite de l'argument 'this' (arg0). Vous n'êtes pas strictement tenu de suivre cette convention, mais toute méthode virtuelle sur un type de référence nécessitera certainement callvirt.
À l'exception des méthodes virtuelles sur les classes scellées. –
Si vous utilisez call dans une méthode dynamique sur une méthode virtuelle, le runtime lève une exception de sécurité.
Qu'est-ce que cela a à voir avec C#? – SLaks