En primer lugar, un cierto fondo Info:Reflection.Emit.ILGenerator control de excepciones "Deja" instrucción
estoy haciendo un compilador para un proyecto escolar. Ya está funcionando, y estoy gastando un montón de esfuerzo para corregir errores y/u optimizarlo. Recientemente me he encontrado con un problema es que he descubierto que el objeto ILGenerator genera una leave
instrucción adicional cuando se llama a cualquiera de los siguientes métodos: miembros
BeginCatchBlock()
BeginExceptFilterBlock()
BeginFaultBlock()
BeginFinallyBlock()
EndExceptionBlock()
Así, se inicia una instrucción try con una llamada a BeginExceptionBlock()
, agregue un par de cláusulas catch con BeginCatchBlock()
, posiblemente agregue una cláusula finally con BeginFinallyBlock()
, y luego termine la región del código protegido con EndExceptionBlock()
.
Los métodos enumerados generan automáticamente una instrucción leave
que se bifurca a la primera instrucción después de la instrucción try. No quiero esto, por dos razones. Uno, porque siempre genera una instrucción leave
no optimizada, en lugar de una instrucción leave.s
, incluso cuando se ramifica a solo dos bytes de distancia. Y dos, porque no puedes controlar a dónde va la instrucción de abandono.
Por lo tanto, si desea realizar una bifurcación a otra ubicación en su código, debe agregar una variable local generada por el compilador, configurarla en función de dónde desee ingresar dentro de la instrucción try, deje EndExceptionBlock()
autogenerar la instrucción leave
, y luego genera una instrucción switch debajo del bloque try. O bien, puede simplemente emite una instrucción de leave
o leave.s
ti mismo, antes de llamar a uno de los métodos anteriores, lo que resulta en un feo e inalcanzables 5 bytes adicionales, así:
L_00ca: leave.s L_00e5
L_00cc: leave L_00d1
Ambas opciones son inaceptables para mí. ¿Hay alguna forma de evitar la generación automática de instrucciones leave
, o de otra forma especificar regiones protegidas en lugar de utilizar estos métodos (que son extremadamente molestos y prácticamente indocumentados)?
EDIT Nota: el compilador C# hace esto, por lo que no es como si hubiera una buena razón para forzarlo. Por ejemplo, si usted tiene .NET 4.5 beta, desmontar el siguiente código y comprobar su aplicación: (bloque de excepción añadió internamente)
public static async Task<bool> TestAsync(int ms)
{
var local = ms/1000;
Console.WriteLine("In async call, before await " + local.ToString() + "-second delay.");
await System.Threading.Tasks.Task.Delay(ms);
Console.WriteLine("In async call, after await " + local.ToString() + "-second delay.");
Console.WriteLine();
Console.WriteLine("Press any key to continue.");
Console.ReadKey(false);
return true;
}
Gracias por la respuesta. Lo dejé abierto porque no estaba seguro de si la solución que encontré (MethodBuilder.SetMethodBody) realmente me funcionaría, no tiene una documentación muy descriptiva. ¡Gracias de nuevo! – aboveyou00