371 Stimmen

Wie InnerException ohne Verlust von Stack-Trace in C# neu auslösen?

Ich rufe über Reflexion eine Methode auf, die eine Ausnahme verursachen kann. Wie kann ich die Ausnahme an meinen Aufrufer weitergeben, ohne dass sie von der Reflexion umschlossen wird?
Ich werfe die InnerException erneut aus, aber dadurch wird die Stapelverfolgung zerstört.
Beispiel-Code:

public void test1()
{
    // Throw an exception for testing purposes
    throw new ArgumentException("test1");
}

void test2()
{
    try
    {
        MethodInfo mi = typeof(Program).GetMethod("test1");
        mi.Invoke(this, null);
    }
    catch (TargetInvocationException tiex)
    {
        // Throw the new exception
        throw tiex.InnerException;
    }
}

12voto

Jürgen Steinblock Punkte 28819

Auf der Grundlage von Paul Turners Antwort habe ich eine Erweiterungsmethode entwickelt

    public static Exception Capture(this Exception ex)
    {
        ExceptionDispatchInfo.Capture(ex).Throw();
        return ex;
    }

die return ex ist nie erreicht, aber der Vorteil ist, dass ich die throw ex.Capture() als Einzeiler, damit der Compiler keine Fehlermeldung ausgibt not all code paths return a value Fehler.

    public static object InvokeEx(this MethodInfo method, object obj, object[] parameters)
    {
        {
            return method.Invoke(obj, parameters);
        }
        catch (TargetInvocationException ex) when (ex.InnerException != null)
        {
            throw ex.InnerException.Capture();
        }
    }

11voto

skolima Punkte 30692

Noch mehr Nachdenken...

catch (TargetInvocationException tiex)
{
    // Get the _remoteStackTraceString of the Exception class
    FieldInfo remoteStackTraceString = typeof(Exception)
        .GetField("_remoteStackTraceString",
            BindingFlags.Instance | BindingFlags.NonPublic); // MS.Net

    if (remoteStackTraceString == null)
        remoteStackTraceString = typeof(Exception)
        .GetField("remote_stack_trace",
            BindingFlags.Instance | BindingFlags.NonPublic); // Mono

    // Set the InnerException._remoteStackTraceString
    // to the current InnerException.StackTrace
    remoteStackTraceString.SetValue(tiex.InnerException,
        tiex.InnerException.StackTrace + Environment.NewLine);

    // Throw the new exception
    throw tiex.InnerException;
}

Beachten Sie, dass dies jederzeit unterbrochen werden kann, da private Felder nicht Teil der API sind. Siehe weitere Diskussion über Mono-Bugzilla .

11voto

kokos Punkte 41886

Erstens: Verlieren Sie die TargetInvocationException nicht - sie ist eine wertvolle Information, wenn Sie die Dinge debuggen wollen.
Zweitens: Wickeln Sie die TIE als InnerException in Ihrem eigenen Ausnahmetyp ein und legen Sie eine OriginalException-Eigenschaft fest, die auf das verweist, was Sie benötigen (und halten Sie den gesamten Aufrufstapel intakt).
Drittens: Lassen Sie den TIE aus Ihrer Methode heraussprudeln.

6voto

Boris Treukhov Punkte 16973

Leute, ihr seid cool Ich werde bald ein Nekromant sein.

    public void test1()
    {
        // Throw an exception for testing purposes
        throw new ArgumentException("test1");
    }

    void test2()
    {
            MethodInfo mi = typeof(Program).GetMethod("test1");
            ((Action)Delegate.CreateDelegate(typeof(Action), mi))();

    }

3voto

Ein weiterer Beispielcode, der die Serialisierung/Deserialisierung von Ausnahmen verwendet. Es ist nicht erforderlich, dass der eigentliche Ausnahmetyp serialisierbar ist. Außerdem verwendet er nur öffentliche/geschützte Methoden.

    static void PreserveStackTrace(Exception e)
    {
        var ctx = new StreamingContext(StreamingContextStates.CrossAppDomain);
        var si = new SerializationInfo(typeof(Exception), new FormatterConverter());
        var ctor = typeof(Exception).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }, null);

        e.GetObjectData(si, ctx);
        ctor.Invoke(e, new object[] { si, ctx });
    }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X