Pchełki VBA, odcinek 16: Enum

https://xpil.eu/4ThZF

Jakiś nieszczęśnik trafił wczoraj na mojego bloga w poszukiwaniu typów wyliczanych w VBA. Przypuszczam, że w efekcie usnął i spóźnił się do pracy, skutkiem czego zapamiętał sobie, żeby nigdy więcej tutaj nie zaglądać. Niemniej jednak nadgryzę temat - a nuż ktoś kiedyś tu trafi szukając typów wyliczanych - i proszę bardzo, wszystko podane jak na tacy.

Na początku powiem, że typy wyliczane w VBA są nieudolną próbą naśladowania "prawdziwych", obiektowo zorientowanych języków programowania - nie należy się jednak spodziewać tutaj takiej elastyczności jaką daje na przykład enum w C#.

Wystarczy tej gry przedwstępnej, przejdźmy do rzeczy.

Typ wyliczany (po naszemu enumeration albo enumerated data type) to nic innego jak zbiór wartości liczbowych (całkowitych), z których każda ma etykietę tekstową, zebranych pod wspólną nazwą.

Przykład:

Enum Jablko
  Antonowka
  Malinowka
  Reneta
  Lobo
  Kosztela
End Enum

W powyższym przykładzie definiujemy sobie typ wyliczany Jablko, a następnie przydzielamy mu pięć wartości typu Integer, od zera do czterech. Antonowka ma wartość 0, Malinowka 1 i tak dalej aż do Koszteli, która ma wartość 4.

Jeżeli z jakichś przyczyn chcemy przypisać wartości ręcznie, nie ma problemu:

Enum Pojazd
 Samochod = 10
 Autobus = 20
 Samolot = 30
 Balon = 40
 Rower = 50
 Deskorolka = 60
End Enum

Tutaj wymusiliśmy numerację elementów typu Pojazd - dopóki wartości będą unikalne, nie ma problemu.

Numerację można też wymusić w nieco inny sposób:

Enum Naczynie
 Kubek = 1
 Miska
 Szklanka
 Talerz
 Wiadro
End Enum

W przykładzie powyżej numeracja elementów rozpocznie się od jedynki (zamiast od zera jak w przykładzie z jabłkiem), kolejne elementy będą dostawać numery 2, 3, 4 i 5.

Można jeszcze inaczej:

Enum Kolor
 Bialy
 Czarny
 Brazowy
 Niebieski = 10
 Zielony
 Czerwony
 Zolty
End Enum

W tym przykładzie kolory Biały, Czarny i Brązowy są ponumerowane 0, 1 i 2, natomiast Niebieski i kolejne dostaną numery 10, 11, 12 i 13.

No dobrze. Wiemy jak utworzyć typ wyliczany, teraz spójrzmy jak go używać:

Enum Jablko
 Antonowka
 Malinowka
 Reneta
 Lobo
 Kosztela
End Enum

Dim j as Jablko

j = Antonowka

Zauważmy, że po wpisaniu znaku równości podpowiadacz (zwany po naszemu IntelliSense) wyświetlił nam pełną listę elementów typu Jablko, dzięki czemu możemy wybrać interesujący nas element z listy.

A po co w ogóle stosuje się typy wyliczane, skoro można zamiast nich użyć stałych? Zamiast definiować typ wyliczany Jablko, wystarczyłoby przecież zdefiniować:

Const ANTONOWKA = 0, MALINOWKA = 1, RENETA = 2, LOBO = 3, KOSZTELA = 4

Jednak w takiej sytuacji zmuszeni bylibyśmy pamiętać nazwy stałych, podczas gdy mając zdefiniowany typ wyliczany wystarczy zapamiętać nazwę tego typu (Jablko), a IntelliSense podpowie nam, jakie wartości są dopuszczalne.

Jedna istotna rzecz, o której czasem się zapomina: zmienna typu wyliczanego jest tak naprawdę zmienną typu Integer, a więc można do niej podstawić dowolną wartość całkowitą, nawet taką, która nie ma swojego odpowiednika wśród elementów typu wyliczanego. Przykład:

Enum Jablko
 Antonowka
 Malinowka
 Reneta
 Lobo
 Kosztela
End Enum

Dim j as Jablko

j = 7

Podstawiliśmy siódemkę a kompilator (ani interpreter) ani kwiknął - jest to całkiem legalna operacja. Jak więc tego uniknąć?

Zazwyczaj stosuje się prosty trick umożliwiający walidację wartości typu wyliczanego:

Enum Jablko
 [_Pierwszy]
 Antonowka
 Malinowka
 Reneta
 Lobo
 Kosztela
 [_Ostatni]
End Enum

Function Walidacja(v As Jablko) As Boolean
 If (v > Jablko.[_Pierwszy] And v < Jablko.[_Ostatni]) Then
  Walidacja = True
 Else
  Walidacja = False
 End If
End Function

Po pierwsze zaważmy, że elementy [_Pierwszy] i [_Ostatni] nie pojawiają się na liście IntelliSense, a to za sprawą podkreślnika na początku ich nazw. Po drugie, ważne żeby [_Pierwszy] był zawsze na początku listy a [_Ostatni] na jej końcu, dzięki czemu funkcja Walidacja zadziała poprawnie.

Na koniec jeszcze słówko o łączeniu atrybutów. Załóżmy, że tworzymy typ wyliczany definiujący elementy do odfiltrowania przy szukaniu samochodu. Jedni będą szukać po roczniku i kolorze, inni po marce i przebiegu, jeszcze inni po rodzaju paliwa, ilości drzwi i kształcie nadwozia.

Przyda się nam tutaj następujący typ wyliczany:

Enum FiltrAuta
 IloscDrzwi = 1
 Przebieg = 2
 Marka = 4
 Model = 8
 RodzajPaliwa = 16
 TypNadwozia = 32
 RodzajSkrzyniBiegow = 64
 Kolor = 128
 Rocznik = 256
End Enum

Jak widać, poszczególne elementy tego typu wyliczanego mają wartości będące całkowitymi potęgami dwójki. Dzięki temu każdy z nich w reprezentacji binarnej ma "zapalony" tylko jeden bit, co pozwala na łączenie tych atrybutów:

Dim a As FiltrAuta
a = RodzajPaliwa Or Model

W powyższym przykładzie zmienna a przyjmie wartość 24 (operacja bitowa OR na tych dwóch wartościach "zapaliła" bity trzeci i czwarty, 2^3 + 2^4 = 24)

A jak sprawdzić czy zmienna zawiera daną opcję? Ano, trzeba zastosować operator And:

If a And FiltrAuta.RodzajSkrzyniBiegow Then
' tutaj blok kodu wykonujący się jeżeli do filtra wybrano rodzaj skrzyni biegów
End If

W ten sposób możemy utworzyć typ wyliczany z maksimum 32 elementami (ponieważ typ Integer kończy się na 2 ^ 31) - jeżeli potrzebujemy więcej elementów, trzeba kombinować dookoła.

To chyba wszystko w temacie typów wyliczanych - na koniec bardzo zachęcam do ich stosowania, ponieważ sprawiają, że kod jest bardziej przejrzysty, a także ułatwiają trzymanie atrybutów w ryzach.

https://xpil.eu/4ThZF

Leave a Comment

Komentarze mile widziane.

Jeżeli chcesz do komentarza wstawić kod, użyj składni:
[code]
tutaj wstaw swój kod
[/code]

Jeżeli zrobisz literówkę lub zmienisz zdanie, możesz edytować komentarz po jego zatwierdzeniu.