723 Stimmen

Warum eine Ausnahme in C# abfangen und erneut auslösen?

Ich schaue mir den Artikel an C# - Datenübertragungsobjekt auf serialisierbaren DTOs.

Der Artikel enthält diesen Teil des Codes:

public static string SerializeDTO(DTO dto) {
    try {
        XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
        StringWriter sWriter = new StringWriter();
        xmlSer.Serialize(sWriter, dto);
        return sWriter.ToString();
    }
    catch(Exception ex) {
        throw ex;
    }
}

Der Rest des Artikels sieht vernünftig aus (für einen Laien), aber der try-catch-throw löst eine WtfException aus... Ist das nicht genau das Gleiche, als würde man Ausnahmen überhaupt nicht behandeln?

Ergo:

public static string SerializeDTO(DTO dto) {
    XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
    StringWriter sWriter = new StringWriter();
    xmlSer.Serialize(sWriter, dto);
    return sWriter.ToString();
}

Oder übersehe ich etwas Grundlegendes zur Fehlerbehandlung in C#? Es ist doch so ziemlich dasselbe wie in Java (abzüglich der geprüften Ausnahmen), oder? ... Das heißt, sie haben beide C++ verfeinert.

Die Stack Overflow-Frage Der Unterschied zwischen dem erneuten Werfen eines parameterlosen Fangs und dem Nichtstun? scheint meine Behauptung zu bestätigen, dass try-catch-throw ein No-op ist.


EDIT:

Nur zur Zusammenfassung für alle, die diesen Thread in Zukunft finden...

NICHT

try {
    // Do stuff that might throw an exception
}
catch (Exception e) {
    throw e; // This destroys the strack trace information!
}

Die Stack-Trace-Informationen können entscheidend sein, um die eigentliche Ursache des Problems zu identifizieren!

DO

try {
    // Do stuff that might throw an exception
}
catch (SqlException e) {
    // Log it
    if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
        // Do special cleanup, like maybe closing the "dirty" database connection.
        throw; // This preserves the stack trace
    }
}
catch (IOException e) {
    // Log it
    throw;
}
catch (Exception e) {
    // Log it
    throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
    // Normal clean goes here (like closing open files).
}

Fangen Sie die spezifischeren Ausnahmen vor den weniger spezifischen (genau wie in Java).


Referenzen:

6voto

Jackson Tarisa Punkte 302

Dies kann nützlich sein, wenn Sie Funktionen für eine Bibliothek oder DLL programmieren.

Diese rethrow-Struktur kann verwendet werden, um den Aufrufstapel absichtlich zurückzusetzen, so dass Sie die Ausnahme, die von einer einzelnen Funktion innerhalb der Funktion ausgelöst wird, nicht mehr von der Funktion selbst erhalten.

Ich denke, dies wird nur verwendet, damit die geworfenen Ausnahmen sauberer sind und nicht in die "Wurzeln" der Bibliothek gehen.

4voto

statler Punkte 1216

Während viele der anderen Antworten gute Beispiele dafür liefern, warum man eine Exception abfangen und erneut auslösen sollte, scheint niemand ein "finally"-Szenario erwähnt zu haben.

Ein Beispiel hierfür ist eine Methode, in der Sie den Cursor setzen (z.B. auf einen Wartecursor), die Methode hat mehrere Exit-Points (z.B. if () return;) und Sie wollen sicherstellen, dass der Cursor am Ende der Methode zurückgesetzt wird.

Zu diesem Zweck können Sie den gesamten Code in ein try/catch/finally einschließen. In der finally-Anweisung setzen Sie den Cursor zurück auf den richtigen Cursor. Damit Sie keine gültigen Ausnahmen begraben, werfen Sie sie in der catch wieder aus.

try
{
    Cursor.Current = Cursors.WaitCursor;
    // Test something
    if (testResult) return;
    // Do something else
}
catch
{
    throw;
}
finally
{
     Cursor.Current = Cursors.Default;
}

1voto

Arsen Khachaturyan Punkte 7275

Umwerfen von Ausnahmen über throw ist nützlich, wenn Sie keinen bestimmten Code haben, um aktuelle Ausnahmen zu behandeln, oder wenn Sie eine Logik haben, um bestimmte Fehlerfälle zu behandeln, aber alle anderen überspringen wollen.

Beispiel:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException)
{
    if (numberText.ToLowerInvariant() == "nothing")
    {
        Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
    }
    else
    {
        throw;
    }
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

Allerdings gibt es auch andere Art dies zu tun, mit Konditionalsätze in Fangblöcken:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException) when (numberText.ToLowerInvariant() == "nothing")
{
    Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

Dieser Mechanismus ist effizienter als das erneute Auslösen einer Ausnahme, weil die .NET-Laufzeitumgebung das Ausnahmeobjekt nicht neu aufbauen muss neu aufbauen muss, bevor es erneut ausgelöst wird.

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