Frage

Ich versuche reflection.emit in C#, um a zu emittieren using (x) { ... } Block.

An dem Punkt, an dem ich in Code bin, muss ich die aktuelle Oberseite des Stapels nehmen, ein Objekt, das idisposable implementiert, diese in einer lokalen Variablen speichern, einen verwendeten Block für diese Variable implementieren und dann einige weitere hinzufügen Code (ich kann mit diesem letzten Teil umgehen.)

Hier ist ein Beispiel für C# Code, das ich in Reflektor zusammenstellen und betrachtete:

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

Das sieht in Reflektor so aus:

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

Ich habe keine Ahnung, wie ich damit umgehen soll ".ry ..." am Ende dort, wenn ich reflection.emit benutze.

Kann mich jemand in die richtige Richtung zeigen?


Bearbeiten: Nachdem ich nach dem Code per E -Mail gefragt habe, werde ich meinen fließenden Schnittstellencode hier veröffentlichen, aber er wird für niemanden viel gebraucht, es sei denn, Sie greifen einige meiner Klassenbibliotheken, und das ist auch ein bisschen Code. Der Code, mit dem ich zu kämpfen hatte, war Teil meines IOC-Projekts, und ich musste eine Klasse generieren, um eine automatische Protokollierung von Methodenanrufen in einem Dienst zu implementieren, im Grunde genommen eine Dekorationsklasse für Dienste, die den Code automatisch generieren.

Die Hauptschleife der Methode, die alle Schnittstellenmethoden implementiert, lautet:

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

Das Ausgeben des BeginnesxceptionBlocks, mit dem Jon geantwortet hat, spuckt aus. Das musste ich also wissen.

Der obige Code stammt von LoggingDecorator.cs, Die IL -Erweiterungen sind meistens in IlgenerateRextensions.designer.cs, und andere Dateien in der Lvk.reflexion Namespace.

War es hilfreich?

Lösung

Ist ILGenerator.BeginExceptionBlock Was werden Sie suchen? Das Beispiel in den Dokumenten deutet darauf hin, dass es der richtige Ansatz ist ...

Andere Tipps

Hier ist ein Beispiel im 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();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top