Benutzer mit den meisten Antworten
try-finally-Blöcke für Erstellung von Ressourcen zur Laufzeit - sinnvoll?

Frage
-
Hallo,
in Delphi bin ich es gewohnt, bei der Verwendung von zur Laufzeit erstellten Ressourcen (Komponenten etc) try-finally-Blöcke zu verwenden.
Beispiel:
Sollte ich diese Angewohnheit in C# beibehalten oder kann ich mir das getrost abgewöhnen?PrjFile = XmlWriter.Create(sFileName, settings); try { PrjFile.WriteStartElement("Test"); ... PrjFile.WriteEndElement(); PrjFile.Close(); } finally { PrjFile = null; }
Antworten
-
Hallo Heiko,
wenn Du die Ausnahme nicht behandeln willst, sondern nur sicherstellen,
dass der Stream geschlossen wird, bietet sich die using Anweisung an,
da Stream-basierte Klassen die IDisposable Schnittstelle anbieten.Der Code verkürzt sich wie im Erstellen von XML-Writern gezeigt:
using (var PrjFile = XmlWriter.Create(sFileName, settings)) { PrjFile.WriteStartElement("Test"); // ... PrjFile.WriteEndElement(); }
Da bei Streams Close selbst Dispose aufruft, ist ein zusätzliches Close nicht erforderlich.
Gruß Elmar
- Als Antwort markiert Heiko Adams Donnerstag, 19. August 2010 12:57
-
Hallo Heiko,
sobald das Ende des Using-Blocks erreicht ist wird dieDispose-Funktion der genutzten Klasse aktiviert, somit ist hier in jedem Fall sichergestellt, dass nach dem Verlassen des using Blocks die Klasse aufgelöst wird.
Du kannst natürlich innerhalb des Using-Blocks weiter hin mit Try-Catch arbeiten um sicher zu gehen, dass deine Schreibzugriffe erfolgreich ausgeführt werden.
MfG, Sebastian Gross- Als Antwort markiert Heiko Adams Donnerstag, 19. August 2010 12:57
Alle Antworten
-
Hallo Heiko,
wenn Du die Ausnahme nicht behandeln willst, sondern nur sicherstellen,
dass der Stream geschlossen wird, bietet sich die using Anweisung an,
da Stream-basierte Klassen die IDisposable Schnittstelle anbieten.Der Code verkürzt sich wie im Erstellen von XML-Writern gezeigt:
using (var PrjFile = XmlWriter.Create(sFileName, settings)) { PrjFile.WriteStartElement("Test"); // ... PrjFile.WriteEndElement(); }
Da bei Streams Close selbst Dispose aufruft, ist ein zusätzliches Close nicht erforderlich.
Gruß Elmar
- Als Antwort markiert Heiko Adams Donnerstag, 19. August 2010 12:57
-
Hallo Heiko,
sobald das Ende des Using-Blocks erreicht ist wird dieDispose-Funktion der genutzten Klasse aktiviert, somit ist hier in jedem Fall sichergestellt, dass nach dem Verlassen des using Blocks die Klasse aufgelöst wird.
Du kannst natürlich innerhalb des Using-Blocks weiter hin mit Try-Catch arbeiten um sicher zu gehen, dass deine Schreibzugriffe erfolgreich ausgeführt werden.
MfG, Sebastian Gross- Als Antwort markiert Heiko Adams Donnerstag, 19. August 2010 12:57
-
Hallo,
Das using verhält sich dort richtig, denn Dispose wird auch bei einer Ausnahme aufgerufen.
Es entspricht manuell codiert in etwa (siehe auch Beschreibung zur using Anweisung):XmlWriter PrjFile = PrjFile = XmlWriter.Create(...); try { PrjFile.WriteStartElement("Test"); // ... PrjFile.WriteEndElement(); } finally { if (prjFile != null) ((IDisposable)prjFile).Dispose(); }
Und ist "richtiger" als Deine derzeitige Vorgehensweise, wo die Instanz eben nicht (sofort) "aufgelöst" wird.Denn es reicht nicht "prjFile" im finally auf null zu setzen. Bei einer Ausnahme wird Close im try gar nicht erst erreicht.
Da Du "nur" null setzt, bleibt die Datei eröffnet und wird erst bei der nächsten Garbage Collection freigegeben.
Das Wann steht jedoch in den Sternen, und so kann es Folgefehler nach sich ziehen, weil die Datei noch geöffnet ist.
(Und das gilt nur, wenn PrjFile die einzige Referenz ist, sonst kann es auch ewig dauern).Ich empfehle Dir:
Gewöhne Dir using dort an, wo die Klasse IDisposable implementiert
und Du bisher try finally verwendet hast.Gruß Elmar
-
Gewöhne Dir using dort an, wo die Klasse IDisposable implementiert und Du bisher try finally verwendet hast.
-
Hallo,
wenn die Klasse es nicht implementiert, so benötigt sie (im Idealfall) keine Sonderbehandlung.
Idealfall insofern, als eine richtige Implementation vorausgesetzt wird,
was bei .NET Framework-Klassen gegeben sein sollte -
bei anderen Quellen sollte/muß man manchmal genauer hinschauen.Die Kernaufgabe von IDisposable ist es unmanaged Ressourcen freizugeben.
Klassen, die vollständig managed sind und keine Verweise auf unmanaged Ressourcen
(hier waren es die Dateihandle, die vom Betriebsystem kommen) werden es nur in
Ausnahmefällen implementieren.
Dort kann man sich auf die Freigabe durch den Garbage Collector verlassen.Und natürlich bleibt immer try ... finally für die Stellen,
bei denen man einen Zustand wiederherstellen möchte -
und kann dies mit using mischen, wenn beides zusammenkommt.Weiteres zu IDisposable aus allen Blickwinkeln findest Du u. a. bei Stackoverflow
Gruß Elmar
-
Hallo Heiko,
das ist wäre eine weitere "Baustelle".
IDisposable sollte man damit keinesfalls verwechseln,
Eine deterministische Finalisierung kennt .NET nicht,
ebensowenig wie Verweiszählern (via IUnknown).Dort kümmert sich unter normalen Umständen ebenfalls die Runtime
über COM Wrapper um die Verwaltungsarbeiten und die Freigabe.
In einigen (nicht sauberen Umgebungen) kann es notwendig sein
dies explizit zu tun, in dem man Marshal. ReleaseComObject aufruft.
Zur Regel sollte man das aber nicht machen, siehe dazu den Artikel:
Marshal.ReleaseComObject Considered Dangerous
wo auch der ältere erwähnt wird:
http://blogs.msdn.com/b/cbrumme/archive/2003/04/16/51355.aspx
der den Unterschied zu IDisposable erläutert.Gruß Elmar