2009-02-02 6 views
30

Wenn ich eine C# -Anwendung schreibe, deren Priorität 1 ist, wie oft sollte ich einen try-catch-Block verwenden?Wie oft sollte ich versuchen und fangen in C#?

Kann ich alle Anweisungen in einer Methode in try-catch-Blöcke einkapseln?

public void SomeMethod() 
{ 
    try 
    { 
     // entire contents of the function 
     // library calls 
     // function calls 
     // variable initialization .. etc 
    } 
    catch (Exception e) 
    { 
     // recover 
    } 
} 

Was sind die Nachteile beim Einpacken alles in Try-Catch-Blöcke?

Antwort

30

Die einzige negative Seite ist, wenn eine Ausnahme tatsächlich ausgelöst wird. Es gibt keinen Overhead zum Umbrechen des Codes, außer wenn Ausnahmen auftreten.

Außerdem möchten Sie Try/Catch nicht für Kontrollfluss verwenden. Stellen Sie sich Folgendes vor (schlechter Code):

try { 

    FileStream fs = File.Open("somefile.txt", FileMode.Open); 

} catch (Exception ex) { 
    MessageBox.Show("The file does not exist. Please select another file"); 
} 

Sie erhalten mehr Leistung von etwas wie File.Exists. wie zum Beispiel:

if(!File.Exists("somefile.txt")) 
    MessageBox.Show("The file does not exist.") 

EDIT: die MSDN direct quote gefunden:

Suchen und in einem anständigen perf Sieg führen kann weg Ausnahme lastigen Code zu entwerfen. Denken Sie daran, dass dies nichts mit try/catch Blöcke zu tun hat: Sie nur die Kosten entstehen, wenn die tatsächliche Ausnahme ausgelöst wird. Sie können so viele versuchen/fangen Blöcke wie Sie wollen. Mit Ausnahmen ist kostenlos, wo Sie Leistung verlieren. Zum Beispiel sollten Sie bleiben weg von Dingen wie Ausnahmen für den Kontrollfluss.

+2

Nun, es gibt * minimale * Overhead. Einige, aber sehr, sehr klein. –

+1

Die schlechte Sache ist, dass der JIT-Compiler keine Inline-Funktionen mit Ausnahmen behandeln kann, die Konstrukte enthalten. –

+17

Es ist möglich, dass die Datei nicht mehr existiert, wenn Sie nach ihr suchen und versuchen, sie zu öffnen. Sie * brauchen * den try-catch-Block, um sicher zu gehen, dass Sie nicht abstürzen. –

1

Es gibt Leistungs Overhead für try Blöcke, wenn Sie das tun, wird Ihre gesamte Funktion langsamer als sonst laufen würde. catch (Exception e) ist auch eine schlechte Idee, wenn Sie fangen Sie wollen etwas Nützliches mit dem, was Sie gefangen, und wenn Sie alle Ausnahmen zu fangen ist es unmöglich zu wissen, was Sie tun sollten.

+0

+1 für die Erklärung der Nachteil zu fangen (Ausnahme e). – jason

+1

Es sei denn, Sie tun etwas wie Logging und werfen es neu. –

8

Eigentlich verwende ich sehr selten einen catch-Block außer für Protokollierungszwecke. finally ist viel häufiger für mich. Die meisten Male, lock oder using tun alles, was ich sinnvollerweise tun kann (und zwar ist das ein finally auch).

Eric Lippert hat eine blog entry on exceptions, die nützlich sein kann.

+1

(oder natürlich für UI-Handler der obersten Ebene) –

1

Sie können dies tun, obwohl es fast in jeder Umgebung, in der Sie arbeiten, einen globalen Ausnahmehandler gibt, in dem Sie auch unbekannte Fehler abfangen und behandeln können.

Für Web-Anwendungen gibt es die Global.asax, für ein Konsolenprogramm, wickeln Sie einfach Ihren Main() in einem try/catch, für Dienstleistungen, gibt es AppDomain.CurrentDomain.UnhandledException usw.

Sie wickeln sollen Abschnitte, in denen Sie vorhersagen können, was die Ausnahme in spezifischeren Blöcken sein könnte, aber die globalen Ausnahmebehandler sollten Ihren Code erheblich vereinfachen und Ihnen helfen.

-1

Sie sollten sie jederzeit verwenden, ein Code kann eine Ausnahme auslösen.

Sie müssen vorsichtig sein, allgemeine Ausnahmen zu fangen ist nie eine gute Idee. Sie müssen entscheiden, welche Ebene Sie behandeln möchten.

Bedeutung, je tiefer Sie sind Sie möchten sehr spezifische Exception zu fangen und allgemeiner zu gehen. In einer Datenbank fangen Sie die SqlException ab. Wenn Sie im Stapel höher gehen, fangen Sie weitere Ausnahmen ab, um die allgemeine Ausnahme ganz oben zu finden.

So können Sie von Fall zu Fall mit jeder Ausnahme umgehen. Eine allgemeine Ausnahme, mit der Sie nicht wissen werden, was Sie damit machen sollen.

+2

* Jede * Codezeile kann eine Ausnahme auslösen. OutOfMemoryException, ThreadAbortException, etc ... Und Sie sollten es nur abfangen, wenn Sie etwas Nützliches tun können. Meistens kannst du nicht. –

4

Generell IMO ist es besser, kleinere Stücke, die außer Kontrolle geraten sind in einen Versuch zu fangen. Wenn Sie sagen:

try 
{ 
    //anything that could possibly go wrong 
    //This kind of thing is only good for Logging IMO and could be done in 
    //Global.asax 
} 

Wie könnten Sie möglicherweise wissen, was in Ihrer Fang-Methode zu tun, denn es könnte alles sein ...

Es ist viel besser zu gehen:

try 
{ 
    //divide user imputs 
} 
catch(DivideByZeroException) 
{ 
    // tell user bad inputs ect.... 
} 
catch (Exception e) 
{ 
    //If you choose to throw the exception you should 
    //*********************** 
    throw; 
    //VS 
    throw ex; //Throw ex will restart the stack trace 
    // recover 
} 
finally 
{ 
    //Clean up resources and continue 
} 

In der schließlich wird immer laufen

+1

Noch besser, um die Ausnahme überhaupt nicht zu erfassen und nur vorher zu überprüfen, ob es existiert – jlembke

3

der Schlüssel zu dieser Frage ist die folgende Zeile ein:

// recover 

Um wiederherstellen zu können, müssen Sie wissen, was und wie wiederhergestellt werden soll. Und das setzt voraus, dass es möglich ist, sich zu erholen, was ziemlich oft nicht der Fall ist.

Sie nur den catch Teil try/catch/finally verwenden sollte eine Ausnahme zu schlucken, wenn Sie wissen, wie die Ausnahme zu behandeln, wenn Sie wissen, wie sich davon zu erholen, und wenn Sie sicher sind, können Sie dies tun, ohne die Anwendung zu verlassen in ein inkonsistenter oder ungültiger Zustand

Wenn Sie dies für alle möglichen Ausnahmen in allen Methodenaufrufen in Ihrer Anwendung tun können, dann gehen Sie direkt weiter, sonst müssen Sie möglicherweise Ihre # 1 Priorität neu denken (manchmal schnell zu scheitern ist eine bessere Option als zu versuchen, eine zu behalten Anwendung lebendig, wenn etwas schief gelaufen ist, und einen viel schwereren Debug-Absturz später haben).

0

Unsere aktuelle Anwendung hat ein ähnliches Mandat: niemals abstürzen. Immer wieder anmutig zurück. Zu diesem Zweck müssen Sie sicherstellen, dass jede Codezeile entweder in einem try-catch-Block eingeschlossen ist oder nur durch Code aufgerufen wird, in den sich die Ausnahmen einfügen können.

Zum Schutz vor nicht abgefangenen Ausnahmen fügen wir außerdem UnhandledExceptionEventHandler an AppDomain.CurrentDomain an.

+1

Ich habe nicht abgestimmt, aber Ihre Aussage "Sie müssen sicherstellen, dass jede Zeile des Codes entweder in einem Versuch eingeschlossen ist- Fangblock ... "beginnt auf dem falschen Fuß. Es ist der zweite Teil der Anweisung, den Sie sicherstellen müssen: Es gibt immer einen Upstream-Exception-Handler. – jdigital

+0

Das scheint ein schlechtes Design zu sein. Nach allem, was ich gelesen habe, sollten Sie try-catch verwenden, um mit der Umgebung umzugehen, Situationen, die von Netzwerk- (oder Server-) Ressourcen abhängen oder von Ihnen nicht kontrolliert werden können. Also werde ich abstimmen. – ConfusedDeer

2

Sie sollten die Ausnahme nur abfangen und stoppen, ohne sie erneut zu starten, wenn Sie sie sinnvoll handhaben können. Ansonsten ist es ein Fehler und es sollte sich ausbreiten.

Ich gehe davon aus, dass wenn sie sagen "diese App sollte nie abstürzen" gibt es eine implizite Anforderung, dass es sich korrekt verhält. Nur das Stoppen von Ausnahmen, die sinnvoll behandelt werden, erfüllt die Anforderung von korrektem Verhalten.

Normalerweise verfügt eine App über einen einzelnen Catch-Block auf oberster Ebene, um nicht behandelte Ausnahmen abzufangen und zu protokollieren. Diese sollten selten auftreten (und vielleicht kann Ihre Anforderung so interpretiert werden, dass diese überhaupt nicht vorkommen sollte). Wenn Sie Ausnahmen an anderer Stelle im Code abfangen und stoppen, riskieren Sie, diese Probleme nicht zu entdecken. Wenn Sie sich anmelden und in vielen anderen Teilen Ihres Codes anhalten, haben Sie eine schlecht konstruierte App aus der Perspektive der Trennung von Bedenken.

23

Dies ist ein großes Thema. Starten Sie here für einige ausgezeichnete Diskussion der Ausnahmebehandlung Best Practices und für einen religiösen Krieg ...

Code Analysis Team Blog

Martin Fowler - Fail Fast

MSDN on Exception Handling

Checked vs Unchecked Exceptions

Meine eigene Meinung hergestellt werden, ist, dass In den meisten Fällen verwenden Sie "versuchen/endlich" viel, aber "fangen" sehr wenig. Das Problem besteht darin, dass Sie Ihre Anwendung versehentlich in einen fehlerhaften Zustand versetzen, wenn Sie versuchen, Ausnahmen in den falschen Instanzen abzufangen und zu behandeln. Verwenden Sie in der Regel dev und test, um zu erfahren, wo Sie tatsächlich eine Ausnahme behandeln müssen. Das sind Orte, die du nicht überprüfen kannst. d. h. Sie sollten nicht wirklich mit nullreference oder feilenotfound arbeiten müssen, da Sie proaktiv nach solchen suchen können. Nur Ausnahmen, die Sie kennen, können passieren, aber Sie können nichts dagegen tun. Um den Status Ihrer Daten zu gewährleisten, lassen Sie sie darüber hinaus abstürzen.

Wenn Sie Ausnahmen verschlucken, heißt das im Allgemeinen, dass Sie Ihr Programm nicht verstehen oder warum Sie eine Ausnahme erhalten. Fangen System.Exception ist das Aushängeschild von Code Gerüche ...

+2

genau, wenn Ihre Anwendung eine Ausnahme auslöst, versuchen Sie zu erfahren, warum diese Ausnahme an erster Stelle geworfen wird, und überprüfen Sie dann (zB wenn die Datei existiert), um sie zu verhindern. –

+0

Wenn die "# 1 Priorität ist nie zu stürzen", dann ist das in der Theorie schön, aber es erfüllt nicht die Anforderungen. Ich bin mir sicher, dass Sie sich über die Anforderungen streiten wollen, aber ich vermute, dass das OP dies nicht als Option hat (wenn er es getan hätte, hätte er das seinem Kunden bereits erklärt ;-) – jdigital

+0

@jdigital - einverstanden. Das ist ein guter Punkt. Seine Frage lautet "stürze niemals ab" – jlembke

-3

try catch in C#:

try{ 

} 
catch (NullReferenceException en) 
{ 

} 
+3

-1: Fange nie 'NullReferenceException' - _fix_ it stattdessen. –

-1
public void functionName 
{ 
    try 
    { 
    //your codes 
    //sometimes 'return' shows exceptions 
    } 
    catch(Exception e) 
    { 
    messagebox.show(e.Tostring()); //to know what is the exception 
    } 
    finally 
    { 
    } 
} 
1

Ich versuche im Allgemeinen try catch Blöcke zu vermeiden. Ich bevorzuge es, Schleifen zu verwenden, um den Benutzer zu zwingen, die Regeln einer Anwendung zu befolgen. Zum Beispiel, wenn ein Benutzer nur sollte ein int eingeben, die gleich oder kleiner als ein int x würde ich verwenden:

if (input > x) 
{ 
    Console.WriteLine("Invalid input. Please enter a number that is equal to or less than x."); 
{...} 
} 

anstatt:

catch (IndexOutOfRangeException) 
{ 
     //error message here 
} 

Aus meiner eigenen persönlichen Erfahrung, die ich finde es einfacher zu schreiben, da man vermeiden kann, Code in einen try Block (Guarding Code) zu kapseln.

Natürlich wird es immer Zeiten geben, in denen die Verwendung von try catch unumgänglich ist - ich mag es nur, wenn es möglich ist.

Verwandte Themen