Anlässlich einer längeren Diskussion im Forum hielt ich es für angebracht, mich etwas tiefer mit dem "try - catch - finally" Konstrukt zu beschäftigen. Da das ganze theoretisch immer sehr trocken ist, wollen wir uns das einmal an einem konkreten Beispiel ansehen. Nehmen wir mal an, wir haben den Pfad einer Datei, die wir öffnen wollen. Was kann denn da alles schief gehen, um das wir uns kümmern müssen? Das wahrscheinlichste ist sicher, dass die Datei gar nicht existiert. Oder besser: nicht mehr, weil irgend ein Bösewicht (oder wir selber ;) ) sie gelöscht oder umbenannt haben. Was können noch für Fehlerfälle auftreten? Vielleicht scheitert das Lesen der Datei, weil einige Sektoren auf der Festplatte defekt sind (eher unwahrscheinlich) oder wir haben keine Berechtigung zum Lesen. (uninteressant bei Einbenutzer-Systemen) Theoretisch könnte man das natürlich weiterführen bis zum Stromausfall, unvorhergesehenem Verlust von Betriebssystemmodulen und so fort. Letzten Endes wird man nie wirklich jeden Fehler beseitigen bzw. auf jeden potentiellen Fehler eine Abhilfe parat haben können. Allerdings lässt sich sehr wohl der Großteil der Fehler behandeln! Als Beispiel könnte ich etwa ein C-Programm von mir aufführen, das ich 1996 geschrieben habe und das täglich etwa vier mal auf eine Datei zugreift. Da gab es bei einigen tausend Zugriffen eine Handvoll (abgefangene) Fehler, weil die Datei nicht vorhanden oder das Laufwerk nicht zugreifbar war, aber ansonsten kam es da zu keinerlei sonstigem Fehler. Warum erzähl ich das? Na, ganz einfach: als Beispiel dafür, dass Fehler meistens gewissen Wahrscheinlichkeiten unterliegen, nach denen sie auftreten. Alltägliche Fehler besitzen eine höhere Wahrscheinlichkeit und sollten daher auch konsequent behandelt werden. Fehler, die in 1000 Jahren einmal auftreten, kümmern in der Regel niemanden bzw. haben einen Dominoeffekt zur Folge. (etwa, wenn man einen laufenden Rechner zum Fenster hinaus wirft ;) ) Um ein System lauffähig zu halten, ist es darum zweckmäßig (und absolut erforderlich!) unter normalen Umständen auftretbare Fehler zu behandeln. Jetzt habe ich aber wirklich lange genug gelabert - jetzt gibt es endlich ein bisschen Code (Erläuterung folgt im Anschluß) Dim Stopuhr As System.Environment Dim Datei As FileStream Dim Dateipfad As String = "c:\" Dim Dateiname As String = "michgibtesnicht.txt" Dim i As Integer Dim Anzahl As Integer = 10000 Anfang = Stopuhr.TickCount For i = 1 To Anzahl Try ' MsgBox("Versuche die Datei zu lesen ...") Datei = File.Open(Dateipfad & Dateiname, FileMode.Open) ' (1) ' MsgBox("Die Datei ist vorhanden. Es kann gelesen werden ...") Catch Ausnahme As FileNotFoundException ' MsgBox("Die Datei existiert am angegebenen Ort nicht!", MsgBoxStyle.Critical, "Fehler !") Catch Ausnahme As DirectoryNotFoundException ' MsgBox("Das angegebene Verzeichnis existiert nicht!", MsgBoxStyle.Critical, "Fehler !") Catch Ausnahme As IOException ' MsgBox(Ausnahme.Message, MsgBoxStyle.Critical, "Fehler !") Catch Ausnahme As Exception ' (2) ' MsgBox(Ausnahme.Message, MsgBoxStyle.Critical, "Fehler !") Finally ' (3) If Not Datei Is Nothing Then Datei.Close() ' MsgBox("Datei wurde ordnungsgemäß geschlossen") End If End Try Next Ende = Stopuhr.TickCount Dim s As String s &= "Try catch dauerte" & vbNewLine & Ende - Anfang & " ms" & vbNewLine Anfang = Stopuhr.TickCount For i = 1 To Anzahl If (Directory.Exists(Dateipfad) = False) Then ' (4) ' MsgBox("Das angegebene Verzeichnis existiert nicht!", MsgBoxStyle.Critical, "Fehler !") ElseIf (File.Exists(Dateipfad & Dateiname) = False) Then ' (5) ' MsgBox("Die Datei existiert am angegebenen Ort nicht!", MsgBoxStyle.Critical, "Fehler !") Else ' (6) Datei = File.Open(Dateipfad & Dateiname, FileMode.Open) Datei.Close() End If Next Ende = Stopuhr.TickCount s &= "if-Abfrage dauerte" & vbNewLine & Ende - Anfang & " ms" MsgBox(s) Um spürbar etwas messen zu können, greifen wir 10.000 mal hintereinander auf die Datei "c:\michgibtesnicht.txt" zu und schauen jeweils mit try/catch bzw. if, wie lange unsere Fehlerbehandlung dauert. Das Resultat hängen wir an einen string, den wir zum Schluß ausgeben. Die auskommentierten MsgBox-Zeilen sind für einen Zeitvergleich unverzichtbar!! Anderenfalls würde er die Benutzerzeit hinzuaddieren, was nicht im Sinne des Erfinders wäre. Bevor ich auf die von mir gemessenen Ergebnisse zu sprechen komme, noch ein paar Erläuterungen zum Code: (1) try = versuch; "Lieber Computer, versuch doch mal, ob du die Datei öffnen kannst ..." aus, ansonsten fehlt die zweite Zeile. try beendet die Ausführung von Code, sobald etwas schief ging, d.h. der Versuch scheiterte. In diesem Fall geht er die aufgeführten Ausnahmen durch, wobei mir so scheint, als würde er sie nicht der Reihe nach durchgehen, sondern alphabetisch, d.h. DirectoryNotFoundException vor FileNotFoundException usw., aber egal. Spielt letzten Endes keine Rolle. Zumindest wird geprüft, ob eine der Ausnahmen zutrifft. Falls es sich um eine nicht aufgeführte Ausnahme (z.B. MircosoftException) handelt, dann wird automatisch (2) verwendet. Sofern die Jungs das nicht völlig chaotisch implementiert haben, sollte Exception die Basisklasse aller Excpetions sein (d.h FileNotFoundException ist eine Klasse, die von Exception erbt), was diesen Zusammenhang verdeutlicht: falls eine XYZException fliegt, die wir als Programmierer nicht behandeln, dann kann er (die Basisklasse Exception) immer noch eine Konvertierung durchführen, da ja bekanntlich eine abgeleitete Klasse konvertierbar zur Basisklasse ist. Resultat: die XYZException wird als Exception erkannt und gefangen. Lange Rede, kurzer Sinn: prinzipiell reicht es, nur diese eine Zeile aufzuführen: Catch Ausnahme As Exception Das fängt uns jede Ausnahme, die es zu behandeln gibt; allerdings mit dem Nachteil, dass wir (im Programm) nicht mehr wissen, was genau nun eigentlich los ist/falsch läuft. Aber das ist ein anderes Thema ... (3) finally = letztendlich; Die Abhandlung der if-Abfragen sollte recht schnell vonstatten gehen: Zum Schluß möchte ich die Ergebnisse diskutieren, die bei der Zeitmessung herauskamen: Testdatei war nicht vorhanden vorhanden Try catch 16,14 s 0,53 s if 0,70 s 1,25 s Man sieht also recht schön, dass man try/catch nicht unbedingt dann verwenden sollte, wenn man davon ausgehen kann, dass es mit hoher Wahrscheinlichkeit zu Fehlern kommen wird. Der großte Vorteil ist allerdings, dass man damit recht unbeschwert coden kann. Egal welche Form von Fehler auch kommen mag, man prüft auf allgemein gehaltene Arten von Ausnahmen und muss sich nicht mit manuellen Überprüfungsfunktionen herumplagen (z.B. File.Exists). Ich hoffe damit etwas Licht ins Dunkel gebracht zu haben. Dieser Tipp wurde bereits 17.478 mal aufgerufen.
Anzeige
![]() ![]() ![]() Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! - nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten - Symbol-Galerie mit mehr als 3.200 Icons im modernen Look Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m. |
vb@rchiv CD Vol.6 ![]() ![]() Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! Online-Update-Funktion Entwickler-Vollversionen u.v.m. Tipp des Monats ![]() Manfred Bohn IndexOf für mehrdimensionale Arrays Die generische Funktion "IndexOf" ermittelt das erste Auftreten eines bestimmten Wertes in einem n-dimensionalen Array sevOutBar 4.0 ![]() Vertikale Menüleisten á la Outlook Erstellen von Outlook ähnlichen Benutzer- interfaces - mit beliebig vielen Gruppen und Symboleinträgen. Moderner OfficeXP-Style mit Farbverläufen, Balloon-Tips, u.v.m. |
||||||||||||||||
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein. |