2009-03-14 23 views
12

Tengo el siguiente código C# sencilla:boxeo cuando se utilizan los genéricos en C#

private Stack<Person> m_stack = new Stack<Person>(); 

public void Add<T>(T obj) 
    where T : Person 
{ 
    m_stack.Push(obj); 
} 

Esto producirá el siguiente código IL:

.method public hidebysig instance void 
      Add<(ConsoleApplication1.Person) T>(!!T obj) cil managed 
    { 
    // Code size  20 (0x14) 
    .maxstack 8 
    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: ldfld  class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person> ConsoleApplication1.Pool::m_stack 
    IL_0007: ldarg.1 
    IL_0008: box  !!T 
    IL_000d: callvirt instance void class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person>::Push(!0) 
    IL_0012: nop 
    IL_0013: ret 
    } // end of method Pool::Add 

Así que mi pregunta es ... ¿por qué el boxeo? (IL_0008) Puedo entender downcasting o incluso error de compilación, pero ¿por qué el boxeo (persona es un tipo de referencia ...)

Gracias de antemano!

Respuesta

4

Creo que es la restricción método genérico que hace esto para usted - pero ...

En cualquier caso, no hay necesidad de que el método genérico en absoluto. Sólo tiene que escribir como:

 
public void Add(Person person) 
{ 
    m_stack.Push(person); 
} 

Usted encontrará que la IL se simplifica, y evita por completo el problema. Si restringe a un tipo de referencia específico, puede usar ese tipo de referencia.

Esto es mucho más fácil de entender, y mucho más clara. Sugeriría evitar la llamada al método genérico a menos que realmente lo necesite. métodos genéricos hacen la clase menos obvio, lo que significa menos legible y fácil de mantener en el largo plazo, y más difícil de usar.

+0

@ Reed: Sí, así es como resolví el problema, pero tenía curiosidad por saber por qué el tipo de referencia está encasillado (no tiene ningún sentido) ... –

+0

Creo que es una implementación de cómo funcionan los métodos genéricos. Tenga en cuenta que es boxeo T, no persona. Nunca está boxeo/unboxing su clase, pero es algo "extra" que termina en allí en las llamadas a métodos genéricos. Sin embargo, no estoy seguro de por qué. –

30

Extracto de ECMA-335 Partición III 4,1

Si typeTok es un tipo de referencia, la instrucción cuadro no hace nada.

donde typeTok es !! T en su caso.

Supongo que cuando el compilador compila el código, siempre llama al box independientemente de si el tipo del operando es de tipo de referencia o no. Debido a la semántica de la caja instrucción , el resultado deseado es siempre garantizada.

+0

esta es la respuesta correcta. – JaredPar

+0

+1 Buen trabajo rastreando esto. Buena información. ¿Esta instrucción también sería eliminada por el JIT, o hace que se deje una instrucción noop en su lugar? –

Cuestiones relacionadas