Question

Je suis en train d'utiliser Reflection.Emit en C # pour émettre un bloc using (x) { ... }.

Au point où je suis dans le code, je dois prendre le haut courant de la pile, qui est un objet qui implémente IDisposable, stocker cette distance dans une variable locale, mettre en œuvre un bloc à l'aide de cette variable, puis à l'intérieur ajouter un peu plus de code (je peux faire face à cette dernière partie.)

Voici un morceau échantillon C # de code que j'essayé de compiler et de regarder dans le réflecteur:

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 ne sais pas comment faire face à cette partie « .Essayez ... » à la fin il lors de l'utilisation Reflection.Emit.

point que quelqu'un peut me dans la bonne direction?


Modifier : Après demandé 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. Le code que je luttais avec faisait partie de mon projet IoC, et je devais générer une classe pour mettre en œuvre l'enregistrement automatique des appels de méthode sur un service, essentiellement une classe de décorateur pour les services qui génère automatiquement le code.

La boucle principale du procédé, qui met en oeuvre toutes les méthodes de l'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 voulais savoir.

Le code ci-dessus est de LoggingDecorator.cs , les extensions IL sont la plupart du temps dans ILGeneratorExtensions.Designer.cs , et d'autres fichiers dans le LVK.Reflection espace de noms.

Était-ce utile?

La solution

ILGenerator.BeginExceptionBlock ce vous êtes après? L'exemple dans la documentation donne à penser qu'il est la bonne approche ...

Autres conseils

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();
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top