2010-11-17 9 views

Respuesta

4

Puede seguir estas simples reglas, uno por uno para determinar qué se debe utilizar:

  • es el método static? Luego use call.
  • ¿Es el tipo que invoca en un tipo de valor? Luego use call. (Esto no aplicar si se encajona el valor - a continuación, en realidad se está invocando en object o alguna de las interfaces, y esos son los tipos de referencia.)
  • es el método que está invocando declarado virtual o abstract? Luego use callvirt.
  • ¿Está invocando el método a través de una referencia de interfaz? Luego use callvirt.
  • ¿El método que invoca está declarado override, pero ni el método ni el tipo de declaración declararon sealed? Luego use callvirt.

En todos los demás casos, no se requiere un despacho virtual para que puede utilizar call - pero usted debe uso callvirt. He aquí por qué:

El uso de callvirt en métodos no virtuales es equivalente a call excepto cuando el primer argumento es nulo. En ese caso, callvirt lanzará un NullReferenceException inmediatamente, mientras que call no lo hará. Esto tiene sentido, porque callvirt está destinado a ser utilizado en casos en que se desea el despacho de métodos virtuales, y no se puede realizar el envío de métodos virtuales si no se tiene un objeto para realizar una búsqueda de tablas virtuales.

Tenga en cuenta que callvirt aún arrojará una excepción si el primer argumento es nulo, incluso si no es necesaria una búsqueda vtable!

Teniendo en cuenta esta información, utilizando callvirt para todas las invocaciones de métodos no estáticos sobre los tipos de referencia (como el compilador de C# hace) puede ser preferible, ya que causará un NullReferenceException de inmediato en el lugar de llamada en lugar de en algún momento más tarde, cuando this se acostumbra (explícita o implícitamente) dentro del método.

+0

Pero .NET usa "llamada" cuando llama algo así como Point.X. De lo que estoy leyendo aparentemente los métodos de tipo de valor usan "llamar". – Will

+2

Sí, porque esos métodos no son virtuales, por lo que esperaría que el resultado utilizara "llamada". Lee mi respuesta nuevamente (Además, las estructuras * no pueden * tener miembros virtuales ya que no se pueden heredar.) – cdhowie

+0

Eso tiene sentido, gracias. Es extraño que la reflexión muestre que "IsVirtual" es cierto para los métodos struct. – Will

6

De forma predeterminada, el compilador de C# siempre usa callvirt para todo excepto para las llamadas estáticas o de tipo de valor. Esto provoca una comprobación nula implícita del argumento 'this' (arg0). No se requiere estrictamente que sigas esta convención, pero cualquier método virtual en un tipo de referencia definitivamente requerirá callvirt.

+1

Excepto por métodos virtuales en clases selladas. –

0

Si utiliza invocar un método dinámico en un método virtual, el tiempo de ejecución arroja una excepción de seguridad.

Cuestiones relacionadas