2010-06-08 10 views
11

J'essaie d'utiliser Reflection.Emit en C# pour émettre un bloc using (x) { ... }. Au point où je suis en code, j'ai besoin de prendre le sommet actuel de la pile, qui est un objet qui implémente IDisposable, le stocke dans une variable locale, implémente un bloc using sur cette variable, puis à l'intérieur il ajouter un peu plus de codeL'utilisation de Reflection.Emit pour émettre un bloc "using (x) {...}"?

Voici un exemple de C# morceau de code que j'ai essayé de compiler et de regarder dans le réflecteur (je peux faire face à cette dernière partie.):

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

cela ressemble à ce réflecteur:

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

Je n'ai aucune idée de la façon de traiter cette partie ".try ..." à la fin là en utilisant Reflection.Emit.

Quelqu'un peut-il me diriger dans la bonne direction?


Modifier: Après posé des questions sur le code par e-mail, je posterai mon code d'interface fluide, mais il ne va pas être beaucoup plus utile à personne, sauf si vous prenez certains de mes bibliothèques de classes, et c'est un peu de code aussi. Le code avec lequel je luttais faisait partie de mon projet IoC, et j'avais besoin de générer une classe pour implémenter la journalisation automatique des appels de méthodes sur un service, essentiellement une classe de décorateur pour les services qui génèrent automatiquement le code.

La boucle principale de la méthode, qui met en oeuvre toutes les méthodes d'interface, est la suivante:

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 recrache la BeginExceptionBlock que Jon a répondu avec, de sorte que ce que je devais savoir.

Le code ci-dessus provient de LoggingDecorator.cs, les extensions IL sont principalement dans ILGeneratorExtensions.Designer.cs et d'autres fichiers dans l'espace de noms LVK.Reflection.

Répondre

11

Est-ce que vous voulez ILGenerator.BeginExceptionBlock? L'exemple dans les docs suggère que c'est la bonne approche ...

+0

Oui, c'était ce que je recherchais. Merci. Je posterai le code si quelqu'un d'autre cherche quelque chose comme ça. –

+0

A la réflexion, je vais poster mon code, j'ai une bibliothèque complète de méthodes d'extension pour Reflection.Emit donc je vais devoir tout réécrire, je le ferai si quelqu'un le demande, mais mon code actuel ne sera probablement utile à personne d'autre qu'à moi. –

0

Voici un exemple, dans le code.

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