2009-09-09 4 views
11

Alguien alguna idea de por qué un método genérico que restringe T a clase tendría instrucciones de boxeo en el código MSIL generado?¿Por qué el método genérico con constancia de T: clase resulta en el boxeo?

Estaba bastante sorprendido por esto ya que seguramente debido a que T se está restringiendo a un tipo de referencia, el código generado no debería necesitar realizar ningún boxeo.

Aquí es el código C#:

protected void SetRefProperty<T>(ref T propertyBackingField, T newValue) where T : class 
{ 
    bool isDifferent = false; 

    // for reference types, we use a simple reference equality check to determine 
    // whether the values are 'equal'. We do not use an equality comparer as these are often 
    // unreliable indicators of equality, AND because value equivalence does NOT indicate 
    // that we should share a reference type since it may be a mutable. 

    if (propertyBackingField != newValue) 
    { 
     isDifferent = true; 
    } 
} 

Aquí está la IL generada:

.method family hidebysig instance void SetRefProperty<class T>(!!T& propertyBackingField, !!T newValue) cil managed 
{ 
    .maxstack 2 
    .locals init (
     [0] bool isDifferent, 
     [1] bool CS$4$0000) 
    L_0000: nop 
    L_0001: ldc.i4.0 
    L_0002: stloc.0 
    L_0003: ldarg.1 
    L_0004: ldobj !!T 
    L_0009: box !!T 
    L_000e: ldarg.2 
    L_000f: box !!T 
    L_0014: ceq 
    L_0016: stloc.1 
    L_0017: ldloc.1 
    L_0018: brtrue.s L_001e 
    L_001a: nop 
    L_001b: ldc.i4.1 
    L_001c: stloc.0 
    L_001d: nop 
    L_001e: ret 
} 

Aviso la caja !! T instrucciones.

¿Alguien alguna idea de por qué esto se está generando?

¿Alguien alguna idea de cómo evitar esto?

Gracias, Phil

+1

Jon está fuera supongo que :-) – Peter

+7

¡He encontrado tu respuesta y era un duplicado! Gran pregunta, por cierto :) Por favor, consulte http://stackoverflow.com/questions/646517/boxing-when-using-generics-in-c –

+3

La esencia de la respuesta que he vinculado es que una instrucción de boxeo en una referencia tipo es efectivamente un nop. Esto permite al compilador emitir libremente instrucciones de boxeo que el JIT puede eliminar para los tipos construidos cerrados que se crearon con un tipo de referencia como argumento de tipo genérico. En su caso (ya que 'T' está restringido como un tipo de referencia) ninguna de las dos instrucciones de boxeo que se emitieron se ejecutará alguna vez. –

Respuesta

2

No tiene que preocuparse por ninguna degradación del rendimiento de la instrucción box porque si su argumento es un tipo de referencia, la instrucción box no hace nada. Aunque todavía es extraño que la instrucción box haya sido creada (¿quizás un diseño más simple/más perezoso en la generación de código?).

0

Creo que esto es concebido por su diseño. No estás limitando a T a una clase específica, por lo que lo más probable es que lo rechaces para objetarlo. De ahí que veas que IL incluye el boxeo.

me gustaría probar este código con el que T: ActualClass

+3

Si lo hace T: ActualClass, ¿por qué molestarse con los genéricos? –

+0

Porque puedes restringir T a niveles más altos ... como iSomeInterface ... –

+1

Chris, si T fuera un objeto, ¿no habría sido empaquetado antes de presionar en la pila? ¿Por qué habría de realizarse alguna operación de boxeo en él? Esperaría que el operador == verifique la igualdad de referencia si T fuera un objeto, por lo que tampoco requeriría operaciones de un/boxing. – Phil

1

no estoy seguro de por qué un boxeo está ocurring. Una forma posible de evitar el boxeo es no usarlo. Solo recompile sin el boxeo. Ej:

.assembly recomp_srp 
{ 
    .ver 1:0:0:0 
} 

.class public auto ansi FixedPBF 
{ 

.method public instance void .ctor() cil managed 
{ 

} 

.method hidebysig public instance void SetRefProperty<class T>(!!T& propertyBackingField, !!T newValue) cil managed 
{ 
    .maxstack 2  
     .locals init (bool isDifferent, bool CS$4$0000) 

     ldc.i4.0 
     stloc.0 
     ldarg.1 
     ldobj !!T 
     ldarg.2 
     ceq 
     stloc.1 
     ldloc.1 
     brtrue.s L_0001 
     ldc.i4.1 
     stloc.0 
     L_0001: ret 

} 

} 

... si se guarda en un archivo recomp_srp.msil sólo tiene que volver a compilar tales como:

ildasm/dll recomp_srp.msil

y funciona bien sin el boxeo en la mi final:

 FixedPBF TestFixedPBF = new FixedPBF(); 

     TestFixedPBF.SetRefProperty<string>(ref TestField, "test2"); 

... por supuesto, me lo cambiaron de protección a pública, que tendría que hacer el cambio de nuevo y proporcionar el resto de su aplicación.

Cuestiones relacionadas