2008-09-29 14 views
40

Fängt die Verwendung die Ausnahme oder wirft sie? d. h.C# "Using" Syntax

Wenn der streamreader eine Ausnahme auslöst, wird sie durch Verwendung von oder ausgelöst, so dass die aufrufende Funktion damit umgehen kann?

Antwort

28

Verwendung von Aussagen essen keine Ausnahmen.

Alle "Verwendung" bedeutet, dass Ihr Objekt auf den using-Block beschränkt ist und automatisch Dispose() für das Objekt aufruft, wenn es den Block verlässt.

Es gibt jedoch ein Problem, wenn ein Thread zwangsweise von einer externen Quelle abgebrochen wird, ist es möglich, dass Dispose nie aufgerufen wird.

+7

Ich bin ziemlich sicher, dass Ihr "Gotcha" nicht korrekt ist. Da die StreamReader-Klasse IDisposable implementiert, sorgt die using-Anweisung für die Entsorgung des Objekts. Da die using-Anweisung wie ein finally-Block funktioniert, spielt es keine Rolle, ob Sie eine Ausnahme oder eine Rückgabe haben. –

+12

Laut http://msdn.microsoft.com/en-us/library/system.threading.threadabortexception.aspx werden catch und finally-Anweisungen weiterhin ausgeführt. Da "using" als endgültiger Block kompiliert wird, wird der in Ihrem Beispiel verwendete Leseprozessor entsorgt. – Uhall

+0

Ich würde mit den beiden vorherigen Kommentaren übereinstimmen. Zusätzlich zum obigen Kommentar von @ Uhall bricht ThreadAbortException den Thread nicht ab, sondern fängt nur die Ausnahme ab, die als Ergebnis ausgelöst wird. –

2

Wenn Sie nicht speziell eine Ausnahme fangen sie den Stapel nach oben geworfen wird, bis etwas tut

15

using ermöglicht die Ausnahme durch zum Kochen bringen. Es verhält sich wie ein Versuch/endlich, wo das gebrauchte Objekt endlich entsorgt wird. Daher ist es nur sinnvoll/nützlich für Objekte, die IDisposable implementieren.

+0

+1. "Versuch/endlich". Vielen Dank! – xagyg

2

Die Verwendung stört nicht die Ausnahmebehandlung, abgesehen von der Bereinigung von Inhalten in ihrem Umfang.

Es behandelt keine Ausnahmen, sondern lässt Ausnahmen passieren.

0

"using" fängt keine Ausnahmen ab, es verfügt nur über Ressourcen im Falle von nicht behandelten Ausnahmen.

Vielleicht ist die Frage, würde es Ressourcen in den Klammern zugeordnet verfügen, wenn ein Fehler auch in der Deklaration aufgetreten ist? Es ist jedoch schwer vorstellbar, dass beides passiert.

60

Wenn Sie eine using-Anweisung sehen, denken Sie an diesem Code:

StreadReader rdr = null; 
try 
{ 
    rdr = File.OpenText("file.txt"); 
    //do stuff 
} 
finally 
{ 
    if (rdr != null) 
     rdr.Dispose(); 
} 

So ist die wirkliche Antwort ist, dass es nicht mit der Ausnahme in dem Körper des mit Block geworfen nichts tut. Es behandelt es nicht oder wiederholt es.

5

Es löst die Ausnahme aus, also muss entweder Ihre containing-Methode damit umgehen oder sie über den Stack übergeben.

try 
{ 
    using (
     StreamReader rdr = File.OpenText("file.txt")) 
    { //do stuff 
    } 
} 
catch (FileNotFoundException Ex) 
{ 
    // The file didn't exist 
} 
catch (AccessViolationException Ex) 
{ 
    // You don't have the permission to open this 
} 
catch (Exception Ex) 
{ 
    // Something happened! 
} 
2

using garantiert * das Objekt erstellt wird am Ende des Blocks angeordnet werden, auch wenn eine Ausnahme ausgelöst wird. Die Ausnahme ist nicht gefangen. Sie müssen jedoch vorsichtig sein, was Sie tun, wenn Sie versuchen, es selbst zu fangen. Da jeder Code, der die Ausnahme abfängt, außerhalb des durch die using-Anweisung definierten Bereichsblocks liegt, ist Ihr Objekt für diesen Code nicht verfügbar.

* Sperre der üblichen Verdächtigen wie Stromausfall, nuklearer Holocaust, etc

1

können Sie sich vorstellen, mit als try ... finally Block ohne catch-Block. Im finally-Block wird IDisposable.Dispose aufgerufen, und da kein catch-Block vorhanden ist, werden alle Ausnahmen in den Stapel geworfen.

3

Alle Exceptions, die im Initialisierungsausdruck der using-Anweisung ausgelöst werden, werden den Methodenbereich und den Aufrufstack wie erwartet weiterleiten.

Eine Sache, auf die man achten sollte, ist, dass, wenn im Initialisierungsausdruck eine Ausnahme auftritt, die Dispose() -Methode für die Ausdrucksvariable nicht aufgerufen wird. Dies ist fast immer das Verhalten, das Sie wünschen, da Sie nicht ein Objekt entsorgen möchten, das nicht tatsächlich erstellt wurde. Unter komplexen Umständen könnte jedoch ein Problem auftreten. Das heißt, wenn mehrere Initialisierungen innerhalb des Konstruktors verborgen sind und einige vor dem Auslösen der Ausnahme erfolgreich sind, wird der Dispose-Aufruf möglicherweise nicht an diesem Punkt ausgeführt. Dies ist jedoch normalerweise kein Problem, da Konstruktoren normalerweise einfach gehalten werden.

+0

Dies ist * immer * das gewünschte Verhalten. Wenn mehrere Initialisierungen innerhalb des Konstruktors verborgen sind, muss der Konstruktor alle erforderlichen Bereinigungen verwalten. Kein externer Code könnte dies möglicherweise tun, da das Objekt nicht tatsächlich erstellt wird. – Joe

+2

@Joe - Ich versuche hier klug zu klingen. Hör auf, die Fehler in meiner Logik aufzuzeigen! –

3

In Ihrem Beispiel, wenn File.OpenText wirft, wird die Disposenicht genannt werden.

Wenn die Ausnahme in //do stuff auftritt, wird die Dispose aufgerufen werden.

In beiden Fällen wird die Ausnahme normalerweise außerhalb des Geltungsbereichs propagiert, wie es ohne die Anweisung wäre.