2010-06-08 4 views
11

Я пытаюсь использовать Reflection.Emit в C# для испускания блока 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 
} 

Я понятия не имею, как бороться с этой частью «.try ...» в конце там, когда используется Reflection.Emit.

Может кто-нибудь указать мне в правильном направлении?


Edit: После того, как вопрос о коде по электронной почте, я выложу мой беглый код интерфейса здесь, но она не будет много пользы никому, если не захватить некоторые из моих библиотек классов, и это тоже немного кода. Код, с которым я боролся, был частью моего проекта 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

Да, это было то, что я был после. Благодарю. Я отправлю код, если кто-нибудь еще ищет что-то вроде этого. –

+0

С другой стороны, я напишу свой код, у меня есть обширная библиотека методов расширения для Reflection.Emit, поэтому мне придется переписать все это, я сделаю это, если кто-то попросит об этом, но мой текущий код вероятно, не будет полезен никому, кроме меня. –

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();