vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#

https://www.vbarchiv.net
Rubrik: Entwicklungsumgebung · Fehlerbehandlung   |   VB-Versionen: VB.NET30.06.05
Fehlerbehandlung mit try-catch bzw. if-Abfrage

Es werden zwei Möglichkeiten der Fehlerbehandlung betrachtet: einmal das altbewährte "if", zum anderen das neue "try / catch" Konstrukt.

Autor:   David MertnerBewertung:  Views:  16.939 
ohne HomepageSystem:  WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11kein Beispielprojekt 

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 ..."
Wenn es klappt, gibt er (bei Entfernen der Kommentare vor den Msgbox)

  • "Versuche die Datei zu lesen ..."
  • "Die Datei ist vorhanden. Es kann gelesen werden ..."
  • "Datei wurde ordnungsgemäß geschlossen"
    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;
    "Lieber PC, bevor alles kaputt geht, mach bitte noch dies, das und jenes ..."
    Falls dieser Absatz vorhanden ist (kann man auch weglassen), wird der angegebene Code in JEDEM Fall ausgeführt, egal ob es nun Fehler gab oder nicht. Es empfiehlt sich daher hier "Aufräumarbeiten" zu erledigen, d.h. Dateien schließen bzw. deren Ströme und so fort.

    Die Abhandlung der if-Abfragen sollte recht schnell vonstatten gehen:
    bei (4) schauen wir nach, ob das Verzeichnis existiert, falls ja, überprüfen wir noch bei (5), ob die Datei vorhanden ist.
    In diesem Fall öffnen wir sie (6).

    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.
     



  • Anzeige

    Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6

    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.
     
     
    Copyright ©2000-2024 vb@rchiv Dieter OtterAlle Rechte vorbehalten.


    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.