Tworzenie i wykorzystanie funkcji i procedur w języku Visual Basic

Transkrypt

Tworzenie i wykorzystanie funkcji i procedur w języku Visual Basic
Ten odcinek Akademii PC Kuriera poświęcony zostanie tworzeniu i wykorzystaniu funkcji i procedur w
języku Visual Basic .NET.
Czym są procedury?
Efektywne tworzenie często polegać będzie na ponownym wykorzystywaniu wcześniej
utworzonego kodu. Stworzone we wcześniejszych projektach rozwiązania w postaci procedur i funkcji
można w szybki sposób zaadoptować do bieżących projektów. Procedury i funkcje będą również
bardzo przydatne do implementacji często powtarzających się w aplikacji zadań czy obliczeń. Każda z
funkcji i procedur określona jest przez jednoznaczną, unikalną w kodzie nazwę, pozwalającej na jej
uruchomienie (wywołania) z poziomu kodu innej procedury. Po wywołaniu procedury jej kod
realizowany jest linia po linii aż do napotkania jednego z wyrażenia kończącego procedurę lub
nakazującego wyjście z procedury. Po wykonaniu procedury kontrola programu zwracana jest do
procedury wywołującej.
Typy procedur w Visual Basic .NET
Procedury w Visual Basic .NET można podzielić na trzy kategorie:
• Procedury Sub (procedury)
• Procedury Function (funkcje)
• Procedury Property (procedury obsługujące własności)
Na potrzeby artykułu ograniczymy się tylko do dwóch pierwszych kategorii. Procedury Sub wykonują
określone przez kod działania, ale nie mogą zwracać wartości do procedur wywołujących. Procedury
obsługujące zdarzenie to również procedury Sub – obsługa zdarzenia polega przecież na wywołaniu
odpowiedniej procedury. W odróżnieniu od Procedur Sub procedury Function mogą natomiast
zwracać wartość do procedury wywołującej.
Dostępność procedur
Możliwość wywołania danej procedury uzależniona jest od użytego w czasie deklaracji modyfikatora
dostępu. Możliwe modyfikatory dostępu dla procedur i funkcji to:
• Public
• Friend
• Private
• Protected
Modyfikator Public zezwala na wywołanie danej procedury lub funkcji przez dowolny kod. Użycie
modyfikatora Friend spowoduje, że dana procedura będzie mogła być wywoływana przez kod
aplikacji i jakikolwiek kod znajdujący się w tym samym assembly (zespół modułów, danych i informacji
o programie). Procedura lub funkcja zadeklarowana jako Private będzie procedurą prywatną dla danej
jednostki kodu. Oznacza to, że będzie ją można wywołać tylko z modułu lub formularza zawierającego
jej deklarację. Modyfikator Protected dotyczy programowania obiektowego w VB i pozwala na
ograniczenie dostępu do procedur - metod danej klasy tylko dla dziedziczonych klas potomnych.
Procedury
Deklaracja procedury Sub ma następującą budowę:
[Modyfikator dostępu] Sub NazwaProcedury (argumenty)
End Sub
Gdzie:
• Modyfikator dostępu jest jednym ze słów kluczowych: Private, Friend, Public, Protect
• NazwaProcedury – jest poprawnie określoną nazwą (nie rozpoczyna się od cyfry, nie zawiera
znaku spacji, spełnia zasady analogiczne do nazw zmiennych)
Argumenty
Dowolna funkcja lub procedura często będzie wymagała danych, w oparciu o które będzie ona
realizowała określone działania. Dane te nazywane są argumentami wejściowymi. Każde wywołanie
funkcji lub procedury, która zawiera w swojej deklaracji argumenty wymagało będzie dostarczenia
odpowiedniej liczby wartości. Argumenty mogą być przekazywane do procedur dwojako: poprzez
wartość (ByVal) lub poprzez referencję (ByRef). Sposób przekazania argumentów określona jest w
deklaracji procedury lub funkcji. Jeśli sposób przekazywania argumentów nie jest jawnie okreśłony, to
domyślnie argumenty przekazywane są poprzez wartość. Lista argumentów składa się więc z ciągu
następujących wyrażeń rozdzielonych przecinkami:
[ByRef lub ByVal] NazwaArgumentu As TypDanych
Jeśli argument przekazywany jest poprzez wartość (ByVal), to do wnętrza procedury przekazywana
jest kopia danych przekazanych jako argumenty wejściowe. Oznacza to, że jeśli kod wnętrza
procedury zmieni tę wartość, to zmiana ta dotyczyć będzie kopii wartości oryginalnej – nie będzie więc
widoczna dla pozostałego kodu.
Jeśli argument przekazywany jest poprzez referencję, to do wnętrza procedury przekazywany jest
wskaźnik do miejsca w pamięci, gdzie przechowywana jest wartość. Jeśli kod wewnątrz procedury
dokona zmiany wartości argumentu, to zmiana ta będzie widoczna dla kodu procedury wywołującej.
Zwróćmy jeszcze uwagę na prosty fakt, iż przekazywanie do procedury jakichkolwiek danych, które
nie są zmiennymi lub wartościami poprzez referencję często prowadzi do błędów logicznych w
aplikacji. Przykładowo, jeśli do procedury przekażemy przez referencję stałą, to pomimo wykonania
operacji na takim argumencie jej wartość nie ulegnie zmianie.
Nie każdy z argumentów musi być obowiązkowy. Jeśli dany parametr jest opcjonalny, to jego
deklaracja na liście argumentów wejściowych powinna rozpoczynać się od słowa kluczowego
Optional. Następnie należy zadeklarować argument i określić jego stałą wartość domyślną. Wartość
ta zostanie użyta, jeśli przy wywołaniu danej funkcji lub procedury wartość dla danego argumentu nie
zostanie określona. Należy zwrócić również uwagę na fakt, że kolejność argumentów obowiązkowych
i opcjonalnych nie może być dowolna w deklaracji. Każdy za wyjątkiem pierwszego argument
opcjonalny musi być poprzedzony innym argumentem opcjonalnym, po ostatnim argumencie
opcjonalnym nie może wystąpić argument obowiązkowy.
Przykład:
Poniższy przykład demonstruje sposób deklaracji procedury, która wyświetla komunikat informujący o
sumie dwóch lub trzech liczb przekazanych jako argumenty wejściowe.
Public Sub Dodaj(ByVal arg1 As Integer, ByVal arg2 As Integer, Optional
ByVal arg3 As Integer = 0)
MessageBox.Show(CStr(arg1 + arg2 + arg3))
End Sub
Uwaga: linie 1 i 2 w powyższym kodzie powinny zostać zapisane w jednym wierszu
Funkcje
Deklaracja funkcji różni się od deklaracji procedury sub zamianą słów sub na function oraz
określeniem typu danych dla wartości zwracanej przez funkcję. Nie należy również zapomnieć różnicy
pomiędzy procedurą a funkcją – możliwości zwrócenia wartości obliczonej przez funkcję. Podobnie jak
w wersji Visual Basic 6.0 można tego dokonać za pomocą przypisania wartości do nazwy funkcji.
Należy jednak pamiętać, że funkcja będzie kontynuowała dalej swoje działanie, aż do pierwszego
napotkania w swym kodzie końca funkcji (End Function) lub polecenia jej opuszczenia (Exit
Function). Nowością w stosunku do wersji Visual Basic 6.0 jest możliwość użycia instrukcji Return.
Instrukcja ta pozwala w szybki sposób zarówno zwrócić wartość jak i zakończyć działanie funkcji.
Przedstawione powyżej wiadomości dotyczące funkcji prezentuje poniższy kod:
Przykład:
Function Suma(ByVal arg1 As Integer, ByVal arg2 As Integer) As Integer
Return arg1 + arg2
End Function
Wywoływanie funkcji i procedur
Przedstawione informacje pozwalają już na napisanie własnej prostej procedury i funkcji. Aby
wywołać utworzoną procedurę lub funkcję należy odwołać się do jej nazwy oraz określić wszystkie
wymagane argumenty wejściowe. Należy pamiętać, że wartości argumentów wejściowych powinny
albo odpowiadać zadeklarowanym typom danych albo umożliwiać dokonanie konwersji niejawnej.
Poniższy kod demonstruje wywołanie uprzednio utworzonej procedury Dodaj oraz funkcji Suma w
obsłudze zdarzenia Load formularza Form1.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dodaj(1, 2)
MessageBox.Show(Suma(3, 4))
End Sub
Uwaga: wiersze 1 i 2 w powyższym kodzie powinny zostać zapisany w jednej linii kodu.
Wnikliwy czytelnik dostrzegł zapewne, że funkcja lub procedura może posiadać kilka argumentów
opcjonalnych. Jak w takim razie wywołać funkcję lub procedurę określając tylko niektóre z nich?
Spójrzmy na deklarację przykładowej funkcji z trzema argumentami opcjonalnymi:
Public Sub ArgumentyOpcjonalne(Optional ByVal arg1 As Integer = 0, Optional
ByVal arg2 As Integer = 0, Optional ByVal arg3 As Integer = 0)
MessageBox.Show(arg1 + arg2 + arg3)
End Sub
Uwaga: wiersze 1 i 2 w powyższym kodzie powinny zostać zapisany w jednej linii kodu.
Poniższy kod prezentuje przykładowe wywołania funkcji ArgumentyOpcjonalne:
•
Pomijamy wszystkie argumenty za wyjątkiem pierwszego
ArgumentyOpcjonalne(1)
•
Przekazujemy tylko drugi z argumentów opcjonalnych ArgumentyOpcjonalne(, 2, )
•
Przekazujemy tylko ostatni z argumentów opcjonalnych ArgumentyOpcjonalne(, , 3)
•
Przekazujemy tylko pierwszy i ostatni z argumentów opcjonalnych ArgumentyOpcjonalne(1, , 3)
•
Przekazujemy wszystkie argumenty opcjonalne ArgumentyOpcjonalne(1, 2, 3)
Tablice argumentów
Implementacja funkcji i procedur wymagających różnej ilości argumentów wejściowych nie zawsze jest
możliwa. Przykładem funkcji, którą trudno byłoby zaimplementować korzystając tylko z argumentów
obowiązkowych i opcjonalnych jest np. sumowanie od dwóch do stu liczb przekazanych jako
argumenty. Deklarowanie takiej funkcji byłoby bardzo uciążliwe. Kolejnym utrudnieniem byłaby zmiana
specyfikacji i uwarunkowań – np. zwiększenie wymagań określających ilość sumowanych liczb
powyżej stu. Często spotykanym problemem, którego nie da się rozwiązać przy pomocy argumentów
opcjonalnych jest również nieznajomość liczby argumentów wejściowych w czasie implementacji
funkcji. Rozwiązaniem powyższych problemów może być tablica parametrów wejściowych.
Przypomnijmy może, że tablica jest to struktura danych pozwalająca odwoływać się do grupy wartości
tego samego typu poprzez nazwę oraz indeks elementu tablicy.
Aby zadeklarować funkcję, której jednym z argumentów jest tablica parametrów należy nazwę
określonego argumentu poprzedzić słowem kluczowym ParamArray. Przekazywana do funkcji tablica
nie posiada narzuconych przez deklarację ograniczeń na wielkość i ilość wymiarów. Sposób
korzystania z tablicy parametrów prezentuje poniższy przykład:
Public Function Srednia(ByVal ParamArray Oceny() As Integer) As Double
Dim i As Integer
Dim suma As Integer
Dim liczbaElementow As Integer
liczbaElementow = UBound(Oceny)
For i = 0 To liczbaElementow
suma = suma + Oceny(i)
Next
Return suma / (liczbaElementow + 1)
End Function
Powyższa oblicza średnią arytmetyczną dowolnej liczby ocen. Funkcja na początku swego działania
korzystając z funkcji Ubound zwracającej maksymalny indeks przekazanej tablicy. Ilość ta
przechowywana jest w zmiennej liczbaElementow. Następnie korzystając z pętli For (tematyka
sterowania programem, instrukcji warunkowych i pętli zostanie omówiona w kolejnym odcinku
Akademii) oblicza sumę wszystkich elementów tablicy. Na końcu swego działania funkcja zwraca
wartość liczbową – średnią – obliczoną jako iloraz sumy i liczby elementów. Ponieważ w Visual Basic
.NET pierwszy z elementów tablicy ma indeks równy 0, dla poprawności obliczeń liczbę elementów
zwiększamy dodatkowo o 1.
Argument ParamArray jest domyślnie opcjonalny - jego pominięcie w czasie wywołania spowoduje, że
do funkcji zostanie przekazana pusta tablica (tablica zawierająca zero elementów). Jako argumentu
wejściowego można użyć tablicy lub wartości rozdzielonych znakiem przecinka. Demonstrują to
następujące przykłady:
•
Przekazanie argumentu jako tablicy
Dim TabWejsciowa() As Integer = {1, 3, 5, 7} ' to jest pięcioelementowa
tablica
Srednia(TabWejsciowa) ' przekazuję tablicę TabWejsciowa do funkcji
•
Przekazanie argumentów jako ciągu wartości
Srednia(1, 3, 5, 7)
Stosowanie tablicy parametrów wymaga jednak przestrzegania następujących reguł:
• Można zadeklarować tylko jeden taki argument
• Argument w postaci tablicy argumentów musi być ostatnim argumentem i jedynym
argumentem opcjonalnym w deklaracji
• Tablica musi być przekazana przez wartość (ByVal)
• Przekazana tablica jest jednowymiarowa
• Wszystkie dane, jakie zawiera tablica muszą być zgodne co do typu z deklaracją
Argumenty przekazywane do funkcji mogą być również tablicami. Następująca funkcja zwraca iloraz
wyznaczników dwóch macierzy o wymiarach 2x2:
Public Function IlorazWyznacznikow(ByVal Macierz1(,) As Integer, ByVal
Macierz2(,) As Integer)
Dim Wyznacznik1 As Double
Dim Wyznacznik2 As Double
Wyznacznik1 = Macierz1(0, 0)*Macierz1(1, 1)-Macierz1(1, 0)*Macierz1(0, 1)
Wyznacznik2 = Macierz2(0, 0)*Macierz2(1, 1)-Macierz2(1, 0)*Macierz2(0, 1)
Return Wyznacznik1 / Wyznacznik2
End Function
Przykładowe wywołanie funkcji IlorazWyznacznikow demonstruje poniższy kod:
Dim W1(,) As Integer = {{1, 2}, {3, 4}}
Dim W2(,) As Integer = {{2, 4}, {6, 8}}
MessageBox.Show(IlorazWyznacznikow(W1, W2))
Kod ten najpierw deklaruje dwie tablice W1 i W2 o wymiarach 2x2 i odpowiednie elementy tablic
wartościami, po czym przekazuje je jako argumenty do funkcji IlorazWyznacznikow.
Zakończenie działania aplikacji
Każda aplikacja powinna dysponować możliwością jej poprawnego zakończenia. Można
oczywiście skorzystać z przycisku zamykania aplikacji na belce tytułowej, ale co zrobić, jeżeli ze
względu na styl okna jest on niedostępny? Aby poprawnie zakończyć działanie aplikacji możesz
skorzystać z metody Exit obiektu Application. Poniższy kod demonstruje przykładową obsługę
działania przycisku zakończ w aplikacji:
Private Sub btnKOniec_Click(ByVal sender As Object, ByVal e As
System.EventArgs) Handles btnKOniec.Click
If messagebox.Show("Czy na pewno chcesz zakończyć działanie
aplikacji?","Koniec?",MessageBoxButtons.YesNo,MessageBoxIcon.Question)=Dial
ogResult.Yes then Application.Exit
End Sub
Uwaga: linie 1 i 2 oraz 3 i 4 powinny zostać zapisane jako jeden wiersz kodu
Funkcje predefiniowane.
Przedstawiona w jednym z odcinków klasa MessageBox pozwalała na wyświetlanie okien
dialogowych. Interakcja z użytkownikiem sprowadzała się więc jedynie do naciśnięcia jednego z
przycisków jakie zawierało wyświetlone okno dialogowe. Visual Basic .NET zawiera wiele funkcji
predefiniowanych z których można budować kod aplikacji. Jedną z takich przykładowych funkcji jest
funkcja InputBox. Funkcja ta służy do wyświetlenia okna dialogowego zawierającego tytuł, opis oraz
pole tekstowe pozwalające na wprowadzenie wartości przez użytkownika. Funkcja ta jest więc kolejną
metodą pozwalającą na pobieranie od użytkownika informacji w czasie działania aplikacji. Aby
wywołać instrukcję InputBox należy skorzystać z następujących argumentów:
Nazwa
argumentu
Prompt
Title
DefaultResponse
XPos
YPos
Znaczenie
Tekst jaki będzie zawierało okno
dialogowe
Tytuł okna dialogowego (napis na
belce tytułowej)
Domyślna odpowiedź. Jeśli argument
ten jest określony, to po wyświetleniu
okna dialogowego będzie ono już
zawierało
w
polu
tekstowym
odpowiedzi wartość tego argumentu.
Współrzędna X lewego górnego rogu
okna (odległość od lewej krawędzi
ekranu)
Wartość
domyślna
Czy
argument
opcjonalny
Nie
Nazwa aplikacji
Tak
Pusty ciąg
znaków
Tak
Połowa
szerokości
ekranu
Jedna
trzecia
wysokości
ekranu
Tak
Tak
Wyświetlone okno będzie również zawierało przyciski OK i Cancel (Anuluj). Funkcja zwraca zmienną
typu String zawierającą dane wprowadzone przez użytkownika. Jeśli użytkownik naciśnie przycisk
Cancel, to funkcja zwróci zmienną typu String o zerowej długości. Znajomość funkcji predefiniowanych
jest niezbędna do efektywnego tworzenia kodu. Na potrzeby ćwiczenia, jakie znajduje się na końću
artykułu przedstawię jeszcze kolejną funkcję – DateDiff. Funkacja DateDiff zwraca liczbę wyrażającą
ilość interwałów czasu, jaka upłynęła pomiędzy dwoma momentami w czasie. Rodzaj interwału (lata,
miesiące, dni, godziny, minuty, sekundy) jak i określenie początku i końca przedziału czasu
przekazywane są jako argumenty. Argument określający interwał może być przekazany jako jedna z
wartości typu wyliczeniowego DateInterval lub jako zmienną typu String. Oprócz powyższych trzech
argumentów do funkcji można również przekazać dwa argumenty opcjonalne: pierwszy dzień tygodnia
oraz pierwszy dzień roku. Argumenty opcjonalne wpływają na zwracaną przez funkcję wartość w
wypadku użycia interwałów tydzień i miesiąc. Do funkcji DateDiff można więc przekazać następujące
argumenty:
Nazwa argumentu
Interval
Date1
Date2
DayOfWeek
WeekOfYear
Znaczenie
Interwał czasu, jaki ma zostać obliczony
Początkowa data okresu
Końcowa data okresu
Pierwszy dzień tygodnia – domyślnie niedziela
Pierwszy dzień roku – domyślnie 1 stycznia
Przykładowe wartości argumentu Interval
Typ wyliczeniowy (enumeracja)
DateInterval.Year
DateInterval.Month
DateInterval.Weekday
DateInterval.Day
DateInterval.Hour
Analogiczna zmienna
typu String
y
m
w
d
h
Rodzaj zwracanego interwału
rok
miesiąc
tydzień
dzień
godzina
Zadanie końcowe tego artykułu polegać będzie na utworzeniu aplikacji, która zwraca liczbę dni życia
użytkownika w oparciu o wprowadzoną przez niego datę urodzenia. Aby wykonać poniższe ćwiczenie
musimy pobrać datę systemową. Można to zrobić przy pomocy przestrzeni nazw system, klasy
datetime i metody now (System.DateTimeNow). Jesteśmy już gotowi do utworzenia projektućwiczenia.
Ćwiczenie
1. Uruchom Visual Studio .NET
2. Wybierz szablon projektu Visual Basic .NET – Windows Application
3. Do formularza Form1 dodaj przycisk
4. Kliknij dwukrotnie na przycisku, aby otworzyć edytor kodu i utworzyć szkielet obsługi
zdarzenie Click dla tego przycisku
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
End Sub
5. W ciele procedury obsługi przycisku (pomiędzy wiersze rozopoczynające się od Private Sub i
End Sub) zadeklaruj zmienne DataDzis i DataUrodzenia. Obie zmienne powinny być typu
Date. Zadeklaruj także zmienną Wynik typu Long. Liczba ta będzie przechowywała wartość
zwracaną przez funkcję DateDiff.
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim dataDzis As Date
Dim dataUrodzenia As Date
Dim wynik As Long
End Sub
6. Do zmiennej DataDzis przypisz bieżącą datę systemową
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim dataDzis As Date
Dim dataUrodzenia As Date
Dim wynik As Long
dataDzis = System.DateTime.Now()
End Sub
7. Do zmiennej DataUrodzenia podstaw datę pobraną od użytkownika przy pomocy funkcji
InputBox. Pamiętaj, że dane zwrócone przez funkcję InputBox są typu String, a zmienna
DataUrodzenia jest zmienną typu Date. Musisz więc odpowiednio skonwertować zwracaną
wartość.
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim dataDzis As Date
Dim dataUrodzenia As Date
Dim wynik As Long
dataDzis = Now()
dataUrodzenia = _
CDate(InputBox("Podaj swoją datę urodzenia: ", _
"Data Urodzenia"))
End Sub
8. Korzystając z funkcji DateDiff oblicz ile dni żyje użytkownik i wyświetl okno dialogowe ze
stosowną informacją dla użytkownika.
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim dataDzis As Date
Dim dataUrodzenia As Date
Dim wynik As Long
dataDzis = Now()
dataUrodzenia = _
CDate(InputBox("Podaj swoją datę urodzenia: ", _
"Data Urodzenia"))
wynik = DateDiff(DateInterval.Day, dataUrodzenia, _
dataDzis)
MessageBox.Show(wynik)
End Sub
9. Uruchom i sprawdź działanie aplikacji. Pamiętaj, że aplikacja nie jest odporna na błedy –
wprowadzenie nieprawidłowej daty spowoduje błąd aplikacji.
W kolejnym - ostatnim odcinku Akademii PC Kuriera poruszymy temat sterowania wykonaniem
programu. Odcinek ten poświęcony będzie instrukcjom warunkowym oraz pętlom w języku Visual
Basic .NET.