Laden...

[gelöst] wozu finally-Block

Erstellt von Bit2_Gosu vor 15 Jahren Letzter Beitrag vor 15 Jahren 2.576 Views
B
Bit2_Gosu Themenstarter:in
116 Beiträge seit 2007
vor 15 Jahren
[gelöst] wozu finally-Block

Hi!

Ihr kennt ja finally Blöcke von nach einem try-catch-Block. Angeblich schreibt man etwas in einen finally Block, wenn man sicherstellen will, dass - ob nun im try-Block eine Exception ausgelöst wurde oder nicht - dieses etwas auf jeden Fall ausgeführt wird.

Dann frage ich mich aber, warum man dieses etwas dann nicht einfach hinter den try-catch-Block schreibt (und zwar nicht in einen finally Block).

Ich schlage vor statt:

try {...} catch {...} finally {tu etwas}

einfach das:

try {...} catch {...} tu etwas
K
174 Beiträge seit 2006
vor 15 Jahren

Hallo Bit2_Gosu,

wenn man zum Beispiel im Catch-Block ein "return" zu stehen hat.

Oft gibt es auch dass Konstrukt try...finally, also ohne einen zugehörigen catch-Bock. Würde man die Anweisung hier hinter dem try... bock schreiben und es tritt eine exception auf, würde die Anweisung nicht erreicht werden.
Oder aber man hat keinen generellen catch-Block und es kommt eine unerwartete Exception.......

Grüße,
Kani

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Bit2_Gosu,

wenn man zum Beispiel im Catch-Block ein "return" zu stehen hat.

... oder auch im try-Block.

herbivore

1.200 Beiträge seit 2007
vor 15 Jahren

Ein Finally-Block wird bei "normalen" Exceptions immer ausgeführt, nachdem diese und der eigentliche try-Block verarbeitet wurden.

Bei manchen Exceptions hilft das jedoch auch nichts, z.B. bei einer StackOverflow Exception.

Shift to the left, shift to the right!
Pop up, push down, byte, byte, byte!

YARRRRRR!

B
Bit2_Gosu Themenstarter:in
116 Beiträge seit 2007
vor 15 Jahren

achso, an solche Fälle hatte ich gar nicht gedacht.
Mal schaun, ob ich finally jemals brauchen werde 😉

Vielen Dank auf jeden Fall!

N
46 Beiträge seit 2007
vor 15 Jahren

Hallo Bit2_Gosu,

der Thread ist zwar schon als geloest gekennzeichnet, mir fehlt hier aber auf jeden Fall noch der Begriff "Ressourcenschutzblock" 😉

Dann wird sich wahrscheinlich auch folgende Frage klaeren:

Mal schaun, ob ich finally jemals brauchen werde 😉

Mal ein ganz einfaches Beispiel, wie so ein Ressourcenschutzblock mit try und finally aussehen kann:


    FileStream fs = new FileStream("file.txt", FileAccess.Read);
    try
    {
         // do something with filestream
    }
    finally
    {
        fs.Close();
    }

Es gibt jetzt 3 Faelle, an denen deutlich wird, was dieses Konstrukt genau macht.

  1. Beim Oeffnen des Filestreams tritt eine Exception auf. Dann wird der Try-Block gar nicht erst durchlaufen und folglich auch der Finally-Block.
  2. Der Filestream kann korrekt geoeffnet werden, im Try-Block tritt keine Exception auf. Der Filestream wird dann auf jeden Fall im Finally-Block korrekt geschlossen.
  3. Der Filestream kann korrekt geoeffnet werden, im Try-Block tritt allerdings eine Exception auf. Trotzdem wird der Filestream korrekt geschlossen.

Fall 1 ist der dabei der eigentlich interessante. Daran wird deutlich, wieso der Filestream unbedingt ausserhalb des try-finally geoeffnet werden muss. Ich habe schon oefter folgendes gesehen:


    try
    {
         FileStream fs = new FileStream("file.txt", FileAccess.Read);
         // do something with filestream
    }
    finally
    {
        fs.Close();
    }

Was passiert, wenn beim oeffnen des Filestreams eine Exception ausgeloest wird? Richtig: Direkt danach wird im Finally-Block versucht einen nicht geoeffneten Filestream zu schliessen. Dann kommt es zu einer neuen Exception.

Deshalb sollte man immer Ressourcen allokieren(in diesem Falle ein File-Handle fuer den Filestream), in einem Try-Block (der nur ausgefuehrt wird, wenn die Allokierung erfolgreich war) mit diesen Ressourcen arbeiten und diese dann im Finally-Block wieder freigeben.

Kurze Anmerkung: Da FileStream das Interface IDisposable implementiert, koennte man obiges Beispiel natuerlich auch mit der Using-Direktive einfacher benutzen, aber es ging ja hier um den grundsaetzlichen Sinn von try-finally 😉

Ich hoffe durch dieses Beispiel wird die Notwendigkteit von try-finally noch ein wenig klarer. Grundsaetzlich gilt, dass die Vorraussetzungen fuer den Finally-Blocks bereits vor dem Try-Block geschaffen werden muss.

Gruesse,

N1ls

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo N1ls,

gut dargestellt. Dazu ein paar Anmerkungen:

Da FileStream das Interface IDisposable implementiert, koennte man obiges Beispiel natuerlich auch mit der Using-Direktive einfacher benutzen, aber es ging ja hier um den grundsaetzlichen Sinn von try-finally 😉

das ist doch gerade der Knackpunkt. Für Ressourcenschutzblöcke wird man meistens using und selten finally benutzen. using wird zwar intern in try/finally umgesetzt, aber im Quellcode taucht finally nicht auf, wenn man using benutzt.

Und selbst wenn ein Objekt kein IDisposable implementiert, muss man nicht auf using verzichten, weil man einfach einen Wrapper schreiben kann, der IDisposable implementiert.

Zu deinem zweiten Codebeispiel: Sicher besteht das Problem, dass eine NullReferenceException auftritt, wenn im Konstruktor eine Exception geworfen wird. Wenn man aber nun dein erstes Beispiel verwendet und trotzdem die Exception des Konstruktors fangen wollen würde, müsste man noch ein try/catch außen rum basteln. Da wäre es schöner, wenn man das zweite Code-Beispiel verwendet und einfach nur ein if (fs != null) vor das fs.Close schreibt.

Bliebe eigentlich nur die Frage, ob using nicht genau so umgesetzt wird. 🙂

herbivore