2009-01-12 5 views
24

Estaba participando en la pregunta de desbordamiento de pila Is everything in .NET an object?.¿Llamar a un método en un tipo de valor resulta en el boxeo en .NET?

Y un cartel (en los comentarios de la respuesta aceptada) parecía pensar que realizar una llamada a un método en un tipo de valor dio como resultado el boxeo. Me señaló Boxing and Unboxing (C# Programming Guide) que no especifica exactamente el caso de uso que estamos describiendo.

No soy de los que confían en una sola fuente, así que solo quería obtener más comentarios sobre la cuestión. Mi intuición es que no hay boxeo, pero mi intuición apesta. : D

elaborar más:

El ejemplo que utilicé fue: hace

int x = 5; 
string s = x.ToString(); // Boxing?? 

boxeo no ocurrir si la estructura en cuestión reemplaza el método heredado del objeto como la respuesta aceptada aquí estados.

Sin embargo, si la estructura no anula el método, se ejecuta un comando "constrain" CIL antes de un callvirt. Según la documentación, OpCodes.Constrained Field, esto se traduce en el boxeo:

Si thisType es un tipo de valor y thisType no implementa el método entonces PTR se eliminan las referencias, en caja, y pasa como el 'presente 'puntero a la instrucción del método callvirt .

+0

Y la razón aquí: http://stackoverflow.com/questions/1359856/why-does-implicitly-calling-tostring-on-a-value-type-cause-a-box-instruction – nawfal

Respuesta

17

Aquí está la IL para su código:

L_0001: ldc.i4.5  // get a 5 on the stack 
L_0002: stloc.0  // store into x 
L_0003: ldloca.s x // get the address of x on the stack 
L_0005: call instance string [mscorlib]System.Int32::ToString() // ToString 
L_000a: stloc.1  // store in s 

Así que la respuesta en este caso es no.

+1

Un importante La nota aquí es que el método ToString no se está llamando contra el valor de x, sino la dirección de x. Observe la instrucción ldloc ** a **. – swax

11

En el caso que ha dado la respuesta es no, como señaló zócalo.

Sin embargo, lo hará si llama a un método a través de un puntero de interfaz.

Considere el código:

interface IZot 
{ 
    int F(); 
} 

struct Zot : IZot 
{ 
    public int F() 
    { 
     return 123; 
    } 
} 

Entonces

Zot z = new Zot(); 
z.F(); 

¿Tiene no resultado en el boxeo:

.locals init (
    [0] valuetype ConsoleApplication1.Zot z) 
L_0000: nop 
L_0001: ldloca.s z 
L_0003: initobj ConsoleApplication1.Zot 
L_0009: ldloca.s z 
L_000b: call instance int32 ConsoleApplication1.Zot::F() 
L_0010: pop 
L_0011: ret 

Sin embargo, esto hace:

IZot z = new Zot(); 
z.F(); 

    .locals init (
     [0] class ConsoleApplication1.IZot z, 
     [1] valuetype ConsoleApplication1.Zot CS$0$0000) 
    L_0000: nop 
    L_0001: ldloca.s CS$0$0000 
    L_0003: initobj ConsoleApplication1.Zot 
    L_0009: ldloc.1 
    L_000a: box ConsoleApplication1.Zot 
    L_000f: stloc.0 
    L_0010: ldloc.0 
    L_0011: callvirt instance int32 ConsoleApplication1.IZot::F() 
    L_0016: pop 
4

Creo que llamar a ToString, Equals y Gethashcode resulta en un boxeo si la estructura no anula los métodos.

+0

simple, directo al grano. debería ser la respuesta correcta – nawfal

7

@ggf31316

"Creo que llamar a ToString, es igual y GetHashCode resultado en el boxeo si la estructura no anulación de los métodos."

He comprobado ToString para usted. Int32 sobrescribe ToString, por lo que hice una estructura que no lo hace. Usé .NET Reflector para asegurarme de que la estructura no estaba anulando mágicamente ToString(), y no era así.

Así que el código fue así:

using System; 

namespace ConsoleApplication29 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyStruct ms = new MyStruct(5); 
      string s = ms.ToString(); 
      Console.WriteLine(s); 
     } 
    } 

    struct MyStruct 
    { 
     private int m_SomeInt; 

     public MyStruct(int someInt) 
     { 
      m_SomeInt = someInt; 
     } 

     public int SomeInt 
     { 
      get 
      { 
       return m_SomeInt; 
      } 
     } 
    } 
} 

Y el MSIL (a través de ILDASM) para el método principal es la siguiente:

IL_0000: ldloca.s ms 
    IL_0002: ldc.i4.5 
    IL_0003: call  instance void ConsoleApplication29.MyStruct::.ctor(int32) 
    IL_0008: ldloca.s ms 
    IL_000a: constrained. ConsoleApplication29.MyStruct 
    IL_0010: callvirt instance string [mscorlib]System.Object::ToString() 
    IL_0015: stloc.1 
    IL_0016: ldloc.1 
    IL_0017: call  void [mscorlib]System.Console::WriteLine(string) 
    IL_001c: ret 

Ahora, a pesar de no llamar boxeo que tendrá lugar, si marque the documentation about a constrained + a call virt, encontrará que dice que el boxeo SÍ tiene lugar. oOo

Cita:

Si thisType es un tipo de valor y thisType no implementa el método entonces PTR se eliminan las referencias, en caja, y pasa como este puntero a la instrucción método callvirt.

Cuestiones relacionadas