2010-06-08 23 views
11

我試圖在C#中使用Reflection.Emit來發出using (x) { ... }塊。使用Reflection.Emit發出「使用(x){...}」塊?

在代碼中,我需要獲取堆棧的當前頂部,它是一個實現IDisposable的對象,將其存儲在局部變量中,在該變量上實現一個使用塊,然後放入它添加更多的代碼

下面是一個示例C#代碼片段我試圖編譯和反射看看(我能處理半句。):

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

這看起來像這樣在反射器:

.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 
} 

我不知道在使用Reflection.Emit時,如何在末尾處理那個「.try ...」部分。

有人能指出我正確的方向嗎?


編輯:問關於後通過電子郵件的代碼,我會在這裏發佈我的流暢界面代碼,但它不會成爲多大用處的人,除非你搶我的一些類庫,這也是一些代碼。我一直在努力的代碼是IoC項目的一部分,我需要生成一個類來實現服務上方法調用的自動日誌記錄,基本上它是一個自動生成代碼的服務的裝飾器類。

方法的主循環,實現所有的接口方法,是這樣的:

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吐出喬恩回答與BeginExceptionBlock,所以這就是我需要知道的東西。

上面的代碼是從LoggingDecorator.cs開始的,IL擴展名主要是ILGeneratorExtensions.Designer.cs,其他文件位於LVK.Reflection命名空間。

回答

11

ILGenerator.BeginExceptionBlock你在追求什麼?文檔中的示例表明這是正確的方法...

+0

是的,這是我以後的事情。謝謝。如果其他人尋找類似的東西,我會發布代碼。 – 2010-06-08 16:13:45

+0

關於第二個想法,我將放棄發佈我的代碼,我有一個用於Reflection.Emit的擴展方法的擴展庫,所以我將不得不重寫它,如果有人要求,我會這樣做,但是我當前的代碼可能對除我以外的任何人都有幫助。 – 2010-06-08 16:16:15

0

下面是代碼示例。

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(); 
相關問題