311 Stimmen

Bewährte Verfahren für das Abfangen und erneute Auslösen von .NET-Ausnahmen

Was sind die besten Praktiken, die beim Abfangen von Ausnahmen und dem erneuten Auswerfen von Ausnahmen zu berücksichtigen sind? Ich möchte sicherstellen, dass die Exception das Objekt InnerException und die Stapelverfolgung werden beibehalten. Gibt es einen Unterschied zwischen den folgenden Codeblöcken in der Art und Weise, wie sie dies handhaben?

try
{
    //some code
}
catch (Exception ex)
{
    throw ex;
}

Vs:

try
{
    //some code
}
catch
{
    throw;
}

14voto

swilliams Punkte 46488

Als Faustregel gilt, dass man das Fangen und Werfen der grundlegenden Exception Objekt. Dies zwingt Sie dazu, mit Ausnahmen etwas klüger umzugehen; mit anderen Worten, Sie sollten einen expliziten Catch für ein SqlException damit Ihr Bearbeitungscode nicht etwas falsch macht mit einer NullReferenceException .

In der realen Welt ist das Fangen von und Protokollierung die Basisausnahme ist auch eine gute Übung, aber vergessen Sie nicht, die ganze Sache zu Fuß zu erledigen, um alle InnerExceptions könnte es haben.

2 Stimmen

Ich denke, es ist am besten, mit unbehandelten Ausnahmen für die Protokollierung zu behandeln, indem Sie die Ausnahmen AppDomain.CurrentDomain.UnhandledException und Application.ThreadException verwenden. Mit großen try { ... } catch(Exception ex) { ... } Blöcke überall bedeutet eine Menge Doppelarbeit. Es hängt davon ab, ob Sie behandelte Ausnahmen protokollieren wollen, in diesem Fall könnte (zumindest minimale) Duplizierung unvermeidlich sein.

0 Stimmen

Außerdem bedeutet die Nutzung dieser Ereignisse, dass Sie do alle unbehandelten Ausnahmen protokollieren, während Sie bei der Verwendung des großen alten try { ... } catch(Exception ex) { ... } Blöcke verwenden, könnten Sie einige übersehen.

10voto

Vinod T. Patil Punkte 2881

Sie sollten immer "throw;" verwenden, um die Ausnahmen in .NET erneut zu werfen,

Siehe dies, http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx

MSIL (CIL) hat im Wesentlichen zwei Anweisungen - "throw" und "rethrow":

  • C#s "throw ex;" wird in MSILs "throw" kompiliert
  • C#s "throw;" - in MSIL "rethrow"!

Grundsätzlich kann ich den Grund sehen, warum "throw ex" den Stack-Trace außer Kraft setzt.

0 Stimmen

Der Link - nun, eigentlich die in dem Link angegebene Quelle -- ist voll von guten Informationen und weist auch auf einen möglichen Grund hin, warum viele denken throw ex; zurückwerfen wird - in Java tut es das! Aber Sie sollten diese Informationen hier einfügen um eine erstklassige Antwort zu erhalten. (Obwohl ich immer noch dabei bin, die ExceptionDispatchInfo.Capture Antwort von jeuoekdcwzfwccu .)

8voto

notlkk Punkte 1191

Ein paar Leute haben einen sehr wichtigen Punkt übersehen - "throw" und "throw ex" tun zwar dasselbe, aber sie geben Ihnen keine entscheidenden Informationen, nämlich die Zeile, in der die Ausnahme passiert ist.

Betrachten Sie den folgenden Code:

static void Main(string[] args)
{
    try
    {
        TestMe();
    }
    catch (Exception ex)
    {
        string ss = ex.ToString();
    }
}

static void TestMe()
{
    try
    {
        //here's some code that will generate an exception - line #17
    }
    catch (Exception ex)
    {
        //throw new ApplicationException(ex.ToString());
        throw ex; // line# 22
    }
}

Wenn Sie entweder ein 'throw' oder 'throw ex' tun, erhalten Sie den Stack-Trace, aber die Zeilennummer wird #22 sein, so dass Sie nicht herausfinden können, welche Zeile genau die Ausnahme ausgelöst hat (es sei denn, Sie haben nur 1 oder wenige Codezeilen im Try-Block). Um die erwartete Zeile #17 in Ihrer Ausnahme zu erhalten, müssen Sie eine neue Ausnahme mit der ursprünglichen Ausnahme Stack Trace werfen.

0 Stimmen

Dass eine einfache throw; hier auch die Zeile 22 statt der Zeile 17 anzeigte, ist wahrscheinlich ein langjähriger Fehler im .NET Framework, der in .NET Core 2.1 behoben wurde ( github.com/dotnet/runtime/issues/9518 ). Abgesehen davon habe ich noch nie einen Fall erlebt, in dem ich die Zeile vom try in der Stacktrace. Die Zeile aus dem Catch und alle weiteren Zeilennummern aus dem Aufrufstapel haben bisher immer ausgereicht.

3voto

1kevgriff Punkte 2221

Ich würde es auf jeden Fall verwenden:

try
{
    //some code
}
catch
{
    //you should totally do something here, but feel free to rethrow
    //if you need to send the exception up the stack.
    throw;
}

So bleibt Ihr Stapel erhalten.

1 Stimmen

Fairerweise muss man sagen, dass ich im Jahr 2008 gefragt habe, wie man den Stapel bewahren kann - und ich habe 2008 eine korrekte Antwort gegeben. Was in meiner Antwort fehlt, ist der Teil, in dem es darum geht, tatsächlich etwas in der Fangfunktion zu tun.

0 Stimmen

@JohnSaunders Das stimmt, wenn und nur wenn Sie no vorher etwas tun throw Sie könnten z.B. ein Disposable bereinigen (wobei Sie es NUR bei einem Fehler aufrufen) und dann die Ausnahme auslösen.

0 Stimmen

@meirion als ich den Kommentar schrieb, war nichts vor dem Wurf. Als das hinzugefügt wurde, habe ich hochgestimmt, aber den Kommentar nicht gelöscht.

3voto

Erick B Punkte 1212

Sie können auch verwenden:

try
{
// Dangerous code
}
finally
{
// clean up, or do nothing
}

Alle ausgelösten Ausnahmen werden an die nächste Ebene weitergegeben, die sie bearbeitet.

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