2010-06-08 22 views
11

Bir using (x) { ... } bloğunu yayınlamak için C# de Reflection.Emit'i kullanmaya çalışıyorum.Bir "kullanarak (x) {...}" bloğu çıkarmak için Reflection.Emit'i kullanma?

Kodda olduğum noktada, IDisposable uygulayan, bunu yerel bir değişkende saklayan, bu değişken üzerinde bir kullanım bloğu uygulayan ve sonra içeride bulunan yığının geçerli üst düzeyini almam gerekiyor. o biraz daha kod eklemek İşte

ben derlemek ve yansıtıcı içinde bakmak çalıştı kod örnek C# parçası (bu son bölümü ile başa çıkabilirim.): Bu yansıtıcı içinde şuna benzer

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'i kullanırken oradaki ".try ..." parçasının nasıl ele alınacağına dair hiçbir fikrim yok.

Birisi bana doğru yönde işaret edebilir mi?


Düzenleme: sonrası burada benim akıcı arayüz kodu göndeririz, e-posta yoluyla kodu hakkında sordum, ama sen benim sınıf kütüphanelerinin bazı kapmak sürece kimseye çok kullanmak gitmiyor ve bu da biraz kod. Çatıştığım kod, IoC projemin bir parçasıydı ve bir hizmeti temelde kodun otomatik olarak oluşturulduğu hizmetler için bir dekoratör sınıfının otomatik olarak günlüğe kaydedilmesi için bir sınıf oluşturmam gerekiyordu.

tüm metodları uygulayan yöntemin ana döngü, şudur ki:

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

bilmem gerekeni yüzden EmitUsing Jon ile cevap BeginExceptionBlock tükürür.

Yukarıdaki kod LoggingDecorator.cs'dan, IL uzantıları çoğunlukla ILGeneratorExtensions.Designer.cs ve diğer dosyalar LVK.Reflection ad alanındadır.

cevap

11

ILGenerator.BeginExceptionBlock durumunuz nedir? Dokümanlardaki örnek, doğru bir yaklaşım olduğunu düşündürmektedir ...

+0

Evet, peşindeyim buydu. Teşekkürler. Kimse böyle bir şey için bakarsa kodu gönderirim. –

+0

İkinci düşünce üzerine, kodumu yayınlamaya bırakacağım, Reflection.Emit için kapsamlı bir uzantı yöntemleri kütüphanesi var, bu yüzden hepsini yeniden yazmam gerekecek, birisi sorarsa yapacağım, ama şu anki kodum Muhtemelen benim için başkalarına yardımcı olmayacaktır. –

0

İşte bir örnek kodda.

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