2010-11-17 3 views

Répondre

4

Vous pouvez suivre ces règles simples, un par un pour déterminer lequel vous devez utiliser:

  • est la méthode static? Ensuite, utilisez call.
  • 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 sur object ou une interface, et ce sont les types de référence.)
  • est la méthode que vous invoquez virtual ou abstract déclarée? Ensuite, utilisez callvirt.
  • 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és sealed? Ensuite, utilisez callvirt.

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.

+0

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

+2

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

+0

Cela a du sens, merci. Juste bizarre que la réflexion montre "IsVirtual" comme vrai pour les méthodes de struct. – Will

6

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.

+1

À l'exception des méthodes virtuelles sur les classes scellées. –

0

Si vous utilisez call dans une méthode dynamique sur une méthode virtuelle, le runtime lève une exception de sécurité.

Questions connexes