2010-06-08 5 views
11

C#에서 Reflection.Emit을 사용하여 using (x) { ... } 블록을 내보내려고합니다.Reflection.Emit을 사용하여 "using (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

네, 이것은 제가 생각했던 것입니다. 감사. 다른 사람이 이와 같은 것을 찾으면 코드를 게시합니다. –

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