2010-06-08 9 views
11

Estoy tratando de usar Reflection.Emit en C# para emitir un bloque using (x) { ... }.Usando Reflection.Emit para emitir un bloque "using (x) {...}"?

En el punto en que estoy en el código, necesito tomar la parte superior actual de la pila, que es un objeto que implementa IDisposable, almacenar esto en una variable local, implementar un bloque de uso en esa variable y luego dentro que añadir algo más de código

Aquí hay una # pieza muestra C de código que he intentado compilar y mirar en el reflector (puedo tratar con la última parte.):

public void Test() 
{ 
    TestDisposable disposable = new TestDisposable(); 
    using (disposable) 
    { 
     throw new Exception("Test"); 
    } 
} 

esta es la siguiente con reflector:

.method public hidebysig instance void Test() cil managed 
{ 
    .maxstack 2 
    .locals init (
     [0] class LVK.Reflection.Tests.UsingConstructTests/TestDisposable disposable, 
     [1] class LVK.Reflection.Tests.UsingConstructTests/TestDisposable CS$3$0000, 
     [2] bool CS$4$0001) 
    L_0000: nop 
    L_0001: newobj instance void LVK.Reflection.Tests.UsingConstructTests/TestDisposable::.ctor() 
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: stloc.1 
    L_0009: nop 
    L_000a: ldstr "Test" 
    L_000f: newobj instance void [mscorlib]System.Exception::.ctor(string) 
    L_0014: throw 
    L_0015: ldloc.1 
    L_0016: ldnull 
    L_0017: ceq 
    L_0019: stloc.2 
    L_001a: ldloc.2 
    L_001b: brtrue.s L_0024 
    L_001d: ldloc.1 
    L_001e: callvirt instance void [mscorlib]System.IDisposable::Dispose() 
    L_0023: nop 
    L_0024: endfinally 
    .try L_0009 to L_0015 finally handler L_0015 to L_0025 
} 

No tengo idea de cómo lidiar con esa parte ".try ..." al final cuando se usa Reflection.Emit.

¿Puede alguien señalarme en la dirección correcta?


Editar: Después preguntó sobre el código por correo electrónico, voy a publicar mi código de interfaz fluida aquí, pero no va a ser de mucha utilidad a nadie a menos que agarrar algunos de mis librerías de clases, y eso también es un poco de código. El código con el que estaba luchando era parte de mi proyecto de IoC, y necesitaba generar una clase para implementar el registro automático de llamadas a métodos en un servicio, básicamente una clase de decorador para servicios que genera automáticamente el código.

El bucle principal del método, que implementa todos los métodos de interfaz, es la siguiente:

foreach (var method in interfaceType.GetMethods()) 
{ 
    ParameterInfo[] methodParameters = method.GetParameters(); 
    var parameters = string.Join(", ", methodParameters 
     .Select((p, index) => p.Name + "={" + index + "}")); 
    var signature = method.Name + "(" + parameters + ")"; 
    type.ImplementInterfaceMethod(method).GetILGenerator() 
     // object[] temp = new object[param-count] 
     .variable<object[]>() // #0 
     .ldc(methodParameters.Length) 
     .newarr(typeof(object)) 
     .stloc_0() 
     // copy all parameter values into array 
     .EmitFor(Enumerable.Range(0, methodParameters.Length), (il, i) => il 
      .ldloc_0() 
      .ldc(i) 
      .ldarg_opt(i + 1) 
      .EmitIf(methodParameters[i].ParameterType.IsValueType, a => a 
       .box(methodParameters[i].ParameterType)) 
      .stelem(typeof(object)) 
     ) 
     // var x = _Logger.Scope(LogLevel.Debug, signature, parameterArray) 
     .ld_this() 
     .ldfld(loggerField) 
     .ldc(LogLevel.Debug) 
     .ldstr(signature) 
     .ldloc(0) 
     .call_smart(typeof(ILogger).GetMethod("Scope", new[] { typeof(LogLevel), typeof(string), typeof(object[]) })) 
     // using (x) { ... } 
     .EmitUsing(u => u 
      .ld_this() 
      .ldfld(instanceField) 
      .ldargs(Enumerable.Range(1, methodParameters.Length).ToArray()) 
      .call_smart(method) 
      .EmitCatch<Exception>((il, ex) => il 
       .ld_this() 
       .ldfld(loggerField) 
       .ldc(LogLevel.Debug) 
       .ldloc(ex) 
       .call_smart(typeof(ILogger).GetMethod("LogException", new[] { typeof(LogLevel), typeof(Exception) })) 
      ) 
     ) 
     .ret(); 
} 

EmitUsing escupe la BeginExceptionBlock que respondió con Jon, y eso es lo que necesitaba saber.

El código anterior es de LoggingDecorator.cs, las extensiones de IL se encuentran principalmente en ILGeneratorExtensions.Designer.cs y otros archivos en el espacio de nombres LVK.Reflection.

Respuesta

11

¿Es ILGenerator.BeginExceptionBlock lo que buscas? El ejemplo en los documentos sugiere que es el enfoque correcto ...

+0

Sí, esto era lo que buscaba. Gracias. Publicaré el código si alguien más busca algo como esto. –

+0

Pensándolo bien, publicaré mi código, tengo una extensa biblioteca de métodos de extensión para Reflection. Emit así que tendré que volver a escribirlo, lo haré si alguien lo solicita, pero mi código actual probablemente no sea útil para nadie más que para mí. –

0

Aquí hay un ejemplo, en el código.

ILGenerator ilg = ...; 

// Begin the 'try' block. The returned label is at the end of the 'try' block. 
// You can jump there and any finally blocks will be executed. 
Label block = ilg.BeginExceptionBlock(); 

// ... emit operations that might throw 

ilg.BeginFinallyBlock(); 

// ... emit operations within the finally block 

ilg.EndExceptionBlock(); 
Cuestiones relacionadas