Autor Beitrag
Raorkon
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 86
Erhaltene Danke: 1



BeitragVerfasst: Di 13.04.10 09:26 
Hallo zusammen,

in einen Beitrag aus diesem Forum wurde erwähnt das man anstatt mit try/Catch mit Using arbeiten kann /soll. Ich würde gern mehr darüber erfahren, welche Vorteile oder Nachteile habe ich davon. Wann macht der jeweilige Einsatz sinn?
norman2306
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 222
Erhaltene Danke: 16

Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
BeitragVerfasst: Di 13.04.10 10:40 
using funktioniert nur mit Objekten, die IDisposable implementieren. Prinzipiell sollte man lieber von using gebrauch machen. Der Vorteil ist, dass das Objekt nach der Nutzung dem GC übergeben wird. Das schont deinen RAM, weil das Objekt definitiv zerstört wird. Die häufigste Anwendung ist bei dem Gebrauch von Streams und sonstigen File-Handles, da somit auch sicher gestellt ist, dass der Zugriff auf das File geschlossen wird, man es also auch in einem anderen Kontext nutzen kann. Also, wenn es geht, using benutzen.

Unabhängig davon kann man trotzdem einen try-catch-Block, wenn man den befürchtet, dass ein unvorhergesehener Fehler auftritt.
JüTho
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2021
Erhaltene Danke: 6

Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
BeitragVerfasst: Di 13.04.10 10:51 
Hallo,

beide Themen haben eigentlich nur wenig miteinander zu tun. Aber die Konsequenzen hängen durchaus zusammen.

try-catch ist die Behandlung von Ausnahmen. Es sollte nicht dazu dienen, den normalen Arbeitsablauf zu steuern. Beispiele:
* if(FileExists) ist sinnvoller, als eine FileNotFoundException auszuwerten.
* if(int.TryParse()) ist sinnvoller als int.Parse oder gar Convert.ToInt32 und auf eine Exception zu reagieren.

Bei using geht es darum, dass eine Instanz automatisch aufgelöst werden soll, ohne dass das im Einzelfall (unabhängig von Fehlern) ausdrücklich geregelt werden muss. Das gilt beispielsweise für:
* Abruf von Daten aus einer Datenbank per DataReader
* Lesen aus einer Datei per FileStream
* genauso Schreiben
* Bilder anzeigen

In allen diesen Fällen wird die benutzte Ressource erst dann freigegeben, wenn ausdrücklich Dispose aufgerufen wird. Das hängt mit der Definition der Klasse zusammen; es gilt für jede Klasse, die mit der Schnittstelle IDisposable definiert wird (ausführliche Begründung steht unter diesem Stichwort in der SDK-Doku/MSDN/Hilfe). Du kannst dir also merken:
Zitat:
Bei jeder Klasse, die IDisposable implementiert hat, ist Dispose ausdrücklich zu verwenden. Dies erspart man sich, wenn man die betreffende Instanz in einen using-Block kapselt, weil dann der Compiler für Dispose sorgt.

Die beiden folgenden Lösungen sind im wesentlichen identisch:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
    StreamWriter sw = new StreamWriter(fileName,true);
    sw.Write(textToAdd);
    sw.Flush();
    sw.Close();
    sw.Dispose();

ausblenden C#-Quelltext
1:
2:
3:
using( StreamWriter sw = new StreamWriter(fileName,true) ) {
    sw.Write(textToAdd);   // Flush erfolgt durch Close automatisch
}   // hier erfolgt Dispose und damit auch Close automatisch

Du siehst: Der using-Block sorgt "nur" dafür, dass Close und Dispose niemals vergessen werden (und dieser Code ist kürzer und schöner).

Mit try-catch-finally hat das eigentlich nichts zu tun. Aber wenn du jetzt Fehlerbehandlung einbauen willst, wird das einfacher.

Gruß Jürgen
Raorkon Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 86
Erhaltene Danke: 1



BeitragVerfasst: Di 13.04.10 10:57 
Super, dankschön für die Erklärung.

ich werde das direkt mal in einen Testprojekt einsetzten.

Ich habe den Try/Catch bisher nur für eine unerwartete Exception eingesetzt. FilenotFound etc. habe ich tatsächlich immer mit IF.... abgefragt. Denoch werde ich vorallem im Bereich der Streams mit Using arbeiten.

Gruß

Ronny
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 13.04.10 11:05 
Normalerweise ist es günstiger (insbesondere weil kompakter auszudrucken) den using Konstrukt zu verwenden anstatt explizit in einem try/catch/finally dispose selber aufzurufen.
Man sollte aber wenn der Aufruf von Dispose selbst eine Exception werfen kann genau überlegen ob nicht doch besser ein ausformulierter try catch verwendet. Grund wenn innerhalb des using Blocks eine Exception auftritt ist diese falls der Dispose der ja auch noch aufgerufen wird auch noch eine Exception wirft weg. Man maskiert sich also so seine eigentliche Fehlerursache und behindert seine Fehlersuche.

Typisches Beispiele wären zum Beispiel WCF Channels. Wenn das öffnen des Channels in einem using Block knallt wird auch das schließen des Channels knallen. Man wird als Fehler immer du Exception des schließens bekommen und muß raten warum das öffnen nicht geht oder das es überhaupt daran lag.
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Di 13.04.10 20:51 
Es gibt eigentlich nichts mehr hinzuzufügen, also nehme ich ich lieber auseinander :mrgreen: .
user profile iconRaorkon hat folgendes geschrieben Zum zitierten Posting springen:
in einen Beitrag aus diesem Forum wurde erwähnt das man anstatt mit try/Catch mit Using arbeiten kann /soll.
catch habe nie erwähnt, es ging um try-finally. catch und using sind weitgehend unabhängige Konzepte.

user profile iconnorman2306 hat folgendes geschrieben Zum zitierten Posting springen:
Der Vorteil ist, dass das Objekt nach der Nutzung dem GC übergeben wird. Das schont deinen RAM, weil das Objekt definitiv zerstört wird.
Nein! Um mein selbst vor ein paar Tagen zu zitieren :) :
user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
IDisposable und GC haben nichts miteinander zu tun... als Notfallleine ruft der Finalizer aber dann doch lieber noch Dispose auf, sollte es der Programmierer vergessen haben :) .


user profile iconJüTho hat folgendes geschrieben Zum zitierten Posting springen:
* if(FileExists) ist sinnvoller, als eine FileNotFoundException auszuwerten.
Eine schlechte Idee, denn Dateisysteme sind asynchron. Und wenn das Fehlen einer Datei nicht als Ausnahme gilt, was dann ;) ?

user profile iconRaorkon hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe den Try/Catch bisher nur für eine unerwartete Exception eingesetzt.
Eine wirklich unerwartete Exception solltest du nicht "verschlingen", da du sie ja gar nicht behandeln kannst. Sie kann höchstens in der aller-äußersten Schicht geloggt und dann das Programm terminiert werden.

user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
Man sollte aber wenn der Aufruf von Dispose selbst eine Exception werfen kann genau überlegen ob nicht doch besser ein ausformulierter try catch verwendet.
Sollte er aber laut den Framework Design Guidelines nie tun :nixweiss: . Hat das WCF wirklich versaubeutelt :D ?

_________________
>λ=
Raorkon Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 86
Erhaltene Danke: 1



BeitragVerfasst: Di 13.04.10 21:11 
Zitat:

if(FileExists) ist sinnvoller, als eine FileNotFoundException auszuwerten.
Eine schlechte Idee, denn Dateisysteme sind asynchron. Und wenn das Fehlen einer Datei nicht als Ausnahme gilt, was dann ;) ?


das würde ich aber nicht unterschreiben! Wie soll ich denn sonst prüfen ob eine Datei vorhanden ist?
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Di 13.04.10 21:23 
Wenn du nur überprüfen willst, ob eine Datei existiert, ohne sie überhaupt öffnen zu wollen, hast du natürlich recht, aber das dürfte nicht der Normalfall sein. Sonst eben durch catch (FileNotFoundException) :nixweiss: .

_________________
>λ=
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 13.04.10 22:09 
Zitat:
Sollte er aber laut den Framework Design Guidelines nie tun :nixweiss: . Hat das WCF wirklich versaubeutelt :D ?


Sollte. Und es wäre schon wenn das machbar wäre. Aber in Dispose sollen ja System Resourcen freigegeben werden und jedes freigaben beinhaltet zumindest ein gewisses Risiko das eine Exception geworfen wird. Die sind für die meisten Resourcen so unwahrscheinlich (z.B Filehandles) das das nahezu irrelevant ist und wenn diese doch auftreten ist das System meißt so im Sack das es auch egal ist wenn das Programm hier mit unschönen Exceptions abschmirrt. Bei den genannten WCF Känalen ist das Risko das man sie nicht richtig schließen kann aber höher (Gegenstelle weg, Netzwerk flattern etc.). Dieses Problem hat man theoretisch auch bei DBConnections obwohl die meist tolleranter sind und in ihrem Close schon die meisten Dinge die schiefgehen können selbst abfackeln(Close auf eine gar nicht geöffnete Verbindung usw.).

Wenn man der Guideline letztlich genüge tun will müßte man wohl einen leeren try .. catch in Dispose basteln der alle Exceptions rigoros schluckt. Diese Lösung ist aber schlimmer als das eigentliche (meist kleine) Problem. ;)
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 14.04.10 00:30 
Fragt sich aber auch, ob solche Exceptions für den User wirklich hilfreich sind. Auf die Information, dass die Verbindung zur DB nicht ordnungsgemäß geschlossen werden konnte, kann ich ja nicht wirklich sinnvoll reagieren - zu ist zu ;) . Und alle erwarteten Exceptions abfangen müssen sie sowieso - zumindest für den Codeteil, der auch über den Finalizer aufgerufen wird, sonst ist gleich der gesamte Prozess vom Fenster.

Fazit: Hoffen, dass man um eine Implementierung von Dispose & Finalize so lange wie möglich herumkommt :D .

_________________
>λ=