Tengo curiosidad por saber por qué sucede esto. Por favor, lee el ejemplo de código siguiente y la IL correspondiente que se emite en los comentarios debajo de cada sección:¿Por qué el compilador C# emite una instrucción callvirt para una llamada al método GetType()?
using System;
class Program
{
static void Main()
{
Object o = new Object();
o.GetType();
// L_0001: newobj instance void [mscorlib]System.Object::.ctor()
// L_0006: stloc.0
// L_0007: ldloc.0
// L_0008: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
new Object().GetType();
// L_000e: newobj instance void [mscorlib]System.Object::.ctor()
// L_0013: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
}
}
¿Por qué el compilador emitirá un callvirt
por primera sección, pero un call
para la segunda sección? ¿Hay alguna razón para que el compilador emita alguna vez una instrucción callvirt
para un método no virtual? Y si hay casos en los que el compilador emitirá un callvirt
para un método no virtual, ¿esto crea problemas para la seguridad de tipo?
muy buena pregunta ... me hizo Fuera del alcance de mis libros. – Gishu
En resumen: Caso (1) invocar método virtual: generar callvirt. Caso (2) invocar el método de instancia en el receptor que acepta nulos: generar callvirt para obtener un cheque nulo barato - sí, esto es seguro. Caso (3) invoque el método de instancia en un receptor conocido que no admite nulos: generar llamada a _avoid_ null check. Su primer ejemplo cae en la categoría (2), su segundo ejemplo cae en la categoría (3). (El compilador sabe que lo nuevo nunca devuelve nulo y, por lo tanto, no es necesario volver a verificar). –
Gracias Eric, la comprobación nula tiene mucho sentido. ¡Tu comentario más la respuesta de Gishu hacen las cosas mucho más claras! :) –