Pregunta
Considere este fragmento C #:
static string input = null;
static string output = null;
static void Main(string[] args)
{
input = "input";
output = CallMe(input);
}
public static string CallMe(string input)
{
output = "output";
return output;
}
Dissassembling usando shows Reflector:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 8
L_0000: nop
L_0001: ldstr "input"
L_0006: stsfld string Reflector_Test.Program::input
L_000b: ldsfld string Reflector_Test.Program::input
L_0010: call string Reflector_Test.Program::CallMe(string)
L_0015: stsfld string Reflector_Test.Program::output
L_001a: ret
}
.method public hidebysig static string CallMe(string input) cil managed
{
.maxstack 1
.locals init (
[0] string CS$1$0000)
L_0000: nop
L_0001: ldstr "output"
L_0006: stsfld string Reflector_Test.Program::output
L_000b: ldsfld string Reflector_Test.Program::output
L_0010: stloc.0
L_0011: br.s L_0013
L_0013: ldloc.0
L_0014: ret
}
La pieza que me intriga es:
L_0010: stloc.0
L_0011: br.s L_0013
L_0013: ldloc.0
Almacena el artículo, ramas a la línea siguiente (lo que habría sido ejecutado de todas formas) y luego se carga de nuevo.
¿Hay una razón para esto?
Solución
Esto sólo ocurre en la depuración, no en su liberación. Sospecho que su para ayudar durante la depuración. Tal vez le permite al mandril puntos de interrupción mediados declaración y ve el valor de retorno.
Tenga en cuenta la versión de lanzamiento tiene IL mucho más concisa:
.method private hidebysig static void Main(string[] args) cil managed
{
.maxstack 8
L_0000: ldstr "input"
L_0005: stsfld string Reflector_Test.Program::input
L_000a: ldsfld string Reflector_Test.Program::input
L_000f: call string Reflector_Test.Program::CallMe(string)
L_0014: stsfld string Reflector_Test.Program::output
L_0019: ret
}
.method public hidebysig static string CallMe(string input) cil managed
{
.maxstack 8
L_0000: ldstr "output"
L_0005: stsfld string Reflector_Test.Program::output
L_000a: ldsfld string Reflector_Test.Program::output
L_000f: ret
}
Otros consejos
Mi conjetura es que se trata de código reutilizable para ejecutar una instrucción de retorno, el compilador ejecuta un salto incondicional a la última línea, y carga el valor de retorno en un registro antes de ejecutar el ret
. El JIT optimizará mejor, creo que el compilador no se molesta en hacer cualquier optimizaciones.