Ćwiczenie VB3.4 Struktura..., obiekt Err, metoda Err.Raise (Strukturalna obsługa wyjątków) Jeśli wpiszemy do okna tekstowego zamiast cyfr litery (np. abc), a następnie spróbujemy ten ciąg znaków przekonwertować na liczbę - instrukcją, np. CSng(txtLiczba.Text) lub Single.Parse(txtLiczba.Text) działanie programu zostanie przerwane i wyświetlony zostanie komunikat Konwersja z ciągu abc na typ Single nie jest prawidłowa przy instrukcji A = CSng(TextBox1.Text) lub Nieprawidłowy format ciągu wejściowego przy instrukcji A = Single.Parse(TextBox1.Text) patrz rys. 1 i 2. Rysunek 1 Rysunek 2 Copyright 2014, mgr inŝ. Janusz Bonarowski 1
Taką sytuację nazywamy błędem czasu wykonania (run time error), a środowisko pracy Visual Basic określa ją jako nie obsłuŝony wyjątek. Po takim komunikacie program zatrzymuje się (zawiesza) - nie moŝe być dalej wykonywany i naleŝy go przerwać. Aby program nie przerywał działania w sposób nieoczekiwany przez uŝytkownika lecz pozwolił dalej np. wprowadzać dane i posługiwać się nim - stosujemy własna strukturę obsługi błędów (tzw. wyjątków). Struktura ta ma postać: ex As Exception. 'Własna obsługa błędów. Finally 'Blok opcjonalny. 'Instrukcje wykonywane niezaleŝnie od tego 'czy błąd się pojawił czy nie pojawił. End Obiekt ex jest to obiekt wyjątek, którego właściwości moŝemy wykorzystywać. Często strukturę tę skracamy opuszczając blok Finally: ex As Exception 'Własna obsługa błędów. End lub jeszcze bardziej upraszczamy gdy nie zamierzamy korzystać z obiektu ex: 'Własna obsługa błędów. End Najprostsze wykorzystanie struktury... i jej efekt na rys. 3: A = CSng(TextBox1.Text) TextBox3.Text = "A = " & A.ToString MsgBox("Proszę poprawić dane", _ MsgBoxStyle.Information, _ "Błąd danych") End Rysunek 3 Copyright 2014, mgr inŝ. Janusz Bonarowski 2
Po odczytaniu takiego komunikatu moŝemy poprawić wpisana wartość, kliknąć przycisk i program będzie kontynuował działanie. Obiekt ex (Exception - wyjątek) Aby posłuŝyć się obiektem ex (Exception - wyjątek) moŝemy wykorzystać jego właściwości Message lub wprost wyświetlić metodą ToString jego zawartość. Kod n = CInt(TextBox1.Text) TextBox3.Text = "N = " & n.tostring ex As Exception 'Komunikat jak na rys. 4 MsgBox("ex.Message: " & ex.message, MsgBoxStyle.Information, _ "Własna obsługa błędów 1") 'Komunikat jak na rys. 5 MsgBox("ex.ToString: " & ex.tostring, MsgBoxStyle.Exclamation, _ "Własna obsługa błędów 1") End przy braku danych w oknie tekstowym wyświetla komunikaty: Rysunek 4. Własna obsługa błędów 1, ex.message Rysunek 5. Własna obsługa błędów 2, ex.tostring Który rodzaj komunikatu wybrać autor programu moŝe zadecydować sam (podpowiadam, Ŝe wersja 1, rys. 4, jest bardziej zrozumiała). Copyright 2014, mgr inŝ. Janusz Bonarowski 3
Obiekt Err Gdy pojawia się błąd czasu wykonania wie o nim wszystko obiekt Err. MoŜemy z tej wiedzy skorzystać. UŜytecznymi dla nas właściwościami tego obiektu są: Err.Number zwraca numer błędu Err.Description zwraca krótki opis błędu. Np. kod: A = CSng(TextBox1.Text) TextBox3.Text = "A = " & A.ToString MsgBox("Err.Number = " & Err.Number & vbcrlf & _ "Err.Description = " & Err.Description) End wyświetli komunikat jak na rys. 6 (porównaj z rys. 4) Rysunek 6 A jeśli komunikat zredagujemy jak w kodzie poniŝej: MsgBox("Proszę poprawić dane." & vbcrlf & _ Err.Description, MsgBoxStyle.Information, "Błąd nr " & Err.Number) UŜytkownik zobaczy go jak na rys. 7 Rysunek 7 Copyright 2014, mgr inŝ. Janusz Bonarowski 4
Komunikat zaleŝny od numeru błędu W bloku instrukcji wykonywanych przy błędzie, moŝemy instrukcją warunkową badać numer błędu (Err.Number) i w zaleŝności od numeru błędu wyświetlać odpowiedni komunikat. Np. kod poniŝej oblicza silnię. Silnia liczby 13 przekracza wartość maksymalnej liczby mieszczącą się w zmiennej typu Integer. Sytuacja taka moŝe generować komunikaty zwracające uwagę uŝytkownikowi na rodzaj błędu - mówiący o niezgodności typów, rys. 8 lub przepełnieniu, rys. 9. Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click Dim s As Integer = 1 Dim i, n As Integer n = CInt(TextBox1.Text) For i = 1 To n s = s * i Next TextBox3.Text = s.tostring If Err.Number = 13 Then 'Komunikat przy błędzie nr 13 (rys. 8) MsgBox("Niezgodność typów." & vbcrlf & _ "Proszę poprawić dane.", MsgBoxStyle.Information, _ "Błąd nr " & Err.Number) ElseIf Err.Number = 6 Then 'Komunikat przy błędzie nr 6, rys. 9 MsgBox("Przepełnienie." & vbcrlf & _ "Liczba jest zbyt duŝa.", MsgBoxStyle.Question, _ "Błąd nr " & Err.Number) Else 'Komunikat przy błędach o pozostałych numerach MsgBox("Proszę poprawić dane." & vbcrlf & _ Err.Description, MsgBoxStyle.Critical, _ "Błąd nr " & Err.Number) End End Sub Rysunek 8 Rysunek 9 Copyright 2014, mgr inŝ. Janusz Bonarowski 5
Samodzielne (programowe) generowanie błędów i ich obsługa Zadanie Obliczyć objętość walca V mając dane: promień podstawy R i wysokość H. Formularz niech ma postać jak na rys. 10. Rysunek 10 Rysunek 11 Gdy tworzymy tę aplikację moŝemy przewidzieć sytuację, gdy uŝytkownik wprowadzi błędne dane, np. wartości spoza zakresu (w zadaniu są to wartości mniejsze lub równe zero). MoŜemy teŝ obsłuŝyć ją programowo bez struktury... : R = CSng(txtR.Text) If R <= 0 Then MsgBox("Błąd danych: R <= 0", MsgBoxStyle.Critical, "Złe dane") Exit Sub W takiej sytuacji naleŝałoby teŝ warunkowo przerwać dalsze wykonywanie programu instrukcją Exit Sub. Efekt takiego rozwiązania pokazuje rys. 11. Podobnie naleŝałoby zabezpieczyć błędnie wprowadzone dane dla wysokości walca H. Wygodniejszym jednak sposobem jest posłuŝenie się strukturą..., a pojawienie się sytuacji, którą uwaŝamy za błędną, zasygnalizować metodą Err.Raise(). Argumenty metody: Err.Raise(Number, Source, Description) W metodzie tej sami definiujemy generującą własny numer błędu (parametr Number), własny komunikat o źródle błędu (parametr Source) i własny opis błędu (parametr Description). PoniewaŜ błędy czasu wykonania (Err.Number) z przedziału od 1 do 1000 zarezerwowane są dla środowiska Visual Basic programista powinien własne numery błędów określać spoza tego przedziału. Na potrzeby tego zadania określajmy numery błędów jako 4-ro cyfrowe, poczynając od 9000. Copyright 2014, mgr inŝ. Janusz Bonarowski 6
Kod Private Sub btnoblicz_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnoblicz.click Dim R, H, V As Single R = CSng(txtR.Text) 'If R <= 0 Then ' MsgBox("Błąd danych: R <= 0", MsgBoxStyle.Critical, _ "Złe dane") ' Exit Sub ' If R <= 0 Then Err.Raise(9000, "Test promienia. ", "Promień R <= 0") 'Err.Raise(Number, Source, Description) H = CSng(txtH.Text) If H <= 0 Then Err.Raise(9001, "Test wysokości.", "Wysokość H <= 0") 'Err.Raise(Number, Source, Description) V = Math.PI * R ^ 2 * H txtv.text = V.ToString ex As Exception MsgBox(Err.Source & Err.Description, _ MsgBoxStyle.Exclamation, "Błąd nr " & _ Err.Number) 'MsgBox("ex.Message: " & ex.message, MsgBoxStyle.Information, _ "błąd nr " & Err.Number) End End Sub Posługiwanie się metodą Raise pozwala w strukturze umieścić tylko jedną instrukcję (np. pojedynczy Message Box) drukującą komunikaty o błędach i róŝnicować ją podczas własnego generowania błędu. W kodzie pokazano teŝ zakomentowane fragmenty kodu do innej obsługi błędów. Proszę odkomentować i zobaczyć róŝnicę w działaniu. Copyright 2014, mgr inŝ. Janusz Bonarowski 7
Programowe generowanie błędów i ich obsługa przy pracy z podprogramami Gdy tworzymy aplikację składającą się z podprogramów i/lub funkcji - moŝliwość samodzielnego (programowego) określania numeru błędu, jego źródła i opisu jest najwygodniejszym sposobem posłuŝenia się strukturą.... Tworzymy ją na jak najwyŝszym poziomie (tu w programie głównym), a pojawienie się błędu w procedurach lub funkcjach obsłuŝymy metodą Err.Raise(). Zadanie to samo Obliczyć objętość walca V mając dane promień podstawy R i wysokość H. Formularz niech ma zatem postać jak na rys. 10. Pole podstawy walca i jego objętość obliczymy posługując się oddzielnymi funkcjami, a błędy, które mogą powstać gdzieś głęboko w funkcjach obsłuŝymy w programie głównym strukturą... z pojedynczą instrukcją drukującą (róŝnorodne) komunikaty o błędach. Kod Private Sub btnoblicz_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles btnoblicz.click Dim R, H, V As Single R = CSng(txtR.Text) H = CSng(txtH.Text) V = Objetosc(PolePodstawy(R), H) txtv.text = V.ToString MsgBox(Err.Source & " - błąd danych: " & Err.Description, _ MsgBoxStyle.Exclamation, "Błąd nr " & _ Err.Number) End End Sub Private Function PolePodstawy(ByRef R As Single) As Single If R <= 0 Then Err.Raise(9000, "Funkcja PolePodstawy", "Promień R <= 0") 'Err.Raise(Number, Source, Description) PolePodstawy = Math.PI * R ^ 2 End Function Private Function Objetosc(ByVal pole As Single, _ ByVal wysokosc As Single) As Single If wysokosc <= 0 Then Err.Raise(9001, "Funkcja Objetość", "Wysokość H <= 0") 'Err.Raise(Number, Source, Description) Objetosc = pole * wysokosc End Function Bibliografia [1] Microsoft Visual Basic.NET, Michael Halvorson, Wydawnictwo RM, Warszawa 2002. Copyright 2014, mgr inŝ. Janusz Bonarowski 8