EnumCzęść NR.7Typ wyliczeniowy, na który często mówię Enum (szkoda , że ta nazwa nie może być przyjęta Puszczam oczko) jest jedną z fajniejszych rzeczy w programowaniu. Dlaczego?

Choćby dlatego , że wyklucza wartości, których nie chcemy. Przykładowo do aplikacji chcemy aby użytkownik podał konkretny miesiąc, ponieważ nasza zmienna byłaby typem wyliczeniowym , a nie np. stringiem .

Nie byłoby mowy o podaniu niewłaściwej wartości, ponieważ sprawnie byśmy je przechwytywali.

Typy wyliczeniowe przydatne są także przy kontrolkach, jak ComboBox, ponieważ z góry wiemy, jakie pola może użytkownik wybrać.

Jednym słowem zamiana niektórych zmiennych z string na typ wyliczeniowy może bardzo usprawnić aplikacje. 

Zapomniałbym dodać , że typ wyliczeniowy fantastycznie się sprawdza we wzorcach. Na przykład do danej kolumny w bazie danych powinny być podane tylko 4 określone wartości. Z typem string istnieje ryzyko umieszczenia innej wartości.

Nie ma też sensu w takich wypadkach tworzyć złożonych systemów. Jaka liczba int będzie odpowiadać numerom miesiąca, czy coś w tym stylu. 

Deklaracja Enum… Typa wyliczeniowego

Enumerator jest definiowany za pomocą słowa kluczowego enum. Po nim podajemy nazwę naszego enum oraz w nawiasach klamrowych piszemy, jakie wartości on przyjmuje.
Oto deklaracja enum KształtChmury, który wyraża typy kształtu chmury.

enum KsztaltChmury 
{
    Pierzasta,
    Warstwowa,
    Klebiaste
}

Moim zdaniem deklaracja typu wyliczeniowego powinna  być traktowana jak deklaracja klasy. Tak aby był porządek w aplikacji.

Użycie typu wyliczeniowego

Po deklaracji enum wypadało go użyć. Używa się dokładnie tak samo, jak inne typy.

KsztaltChmury enum

Z typem wyliczeniowym mogę tworzyć zmienne typu KształtChmury, która może przechowywać parametry typu KształtChmury.

class Chmura 
{
    public KsztaltChmury ksztalt;
}

enum KsztaltChmury 
{
    Pierzasta,
    Warstwowa,
    Klebiaste
}

Zanim będziesz mógł odczytać enum musisz przypisać mu wartość. Chociaż w tym wypadku domyślny konstruktor klasy napisany przez kompilator uzupełni zmienną ksztalt pierwszą wartością typu wyliczeniowego.

Domyślny konstruktor do klasy

Ale tak jak z innymi zmiennymi , żeby zmienna mogła być odczytana musi posiadać jakąś wartość.

KsztaltChmury KC = KsztaltChmury.Warstwowa;
Console.WriteLine(KC);

Można oczywiście utworzyć typ nullable dla konkretnego typu wyliczeniowego. Jeśli jakaś zmienna musi przechowywać brak wartości, to można to rozwiązać w ten sposób.

KsztaltChmury? KC2 = null;

Typ wyliczeniowy może być przerobiony na napis za pomocą metody “ToString()” . Podobnie jak z innymi zmiennymi możemy sprawdzać, czy zmienne wyliczeniowe mają te same wartości (== i !=).

Na typach wyliczeniowych możemy też wykonywać operacje bitowe, o których jeszcze nie wspomniałem na blogu. Jest to  istotne, ale o tym później.

Operacje bitowe na enum
Można też wykonywać operacje arytmetyczne jak dodawanie.

Operacje arytmetyczne
Co zbliża nas do następnego punktu. Jak to możliwe , że typ KsztaltChmury może przechowywać liczbę 4.

Wartości typów wyliczeniowych

Wartości typów enum są liczbami całkowitymi. Czyli  w poprzednim przykładzie “Kłębiasta” wartość enum jest również cyfrą 2.

Domyślne enum zaczyna się od liczby zero, czyli pierwsza wartość napisana przy deklaracji typu wyliczonego równocześnie reprezentuje liczbę 0.

Jeśli z jakiegoś powodu chcesz aby twój enum wyświetlił swoją cyfrę zamiast swojej wartości , musisz wykonać na nim rzutowanie na typ (int).

Rzutowanie na int
Możesz też przypisać swoje wartości liczbowe do enum.

enum KsztaltChmury 
{
    Pierzasta = 10,
    Warstwowa = 22,
    Klebiaste
}

Rzeczywiście to działa.

Z int na Enum
Jednak jaką wartość liczbową ma wartość Kłębiaste …zero? Otóż nie ma wartość 23, czyli kompilator automatycznie do następnych wartości enum dodaje o jeden więcej od poprzedniej wartości.

23 kolejność enum
Enum pozwala na przypisanie większej liczby wartości do tej samej dosłownej  wartości. Np. chmura upierzona, to w sumie to  samo, co chmura pierzasta. Można to zrobić  w ten sposób.

enum KsztaltChmury 
{
    Pierzasta,
    Upierzona = 0,
    Warstwowa,
    Klebiaste
}

…albo w ten. Oczywiście drugie podejście jest lepsze, bo nie musisz wiedzieć jaką wartość liczbową ma dosłowna wartość “Pierzasta”.

enum KsztaltChmury 
{
    Pierzasta,
    Upierzona = Pierzasta,
    Warstwowa,
    Klebiaste
}

Oto przykład kodu, który wyjaśni co stanie się, jeśli przyrównamy Pierzastą wartość do Upierzonej.

Porównanie

Czyli wartość enum “Upierzona” to tylko inny alias do wartość “Pierzasta”.

Wybór liczbowego typu dla typu wyliczeniowego

Domyślnie jest to typ int. Możesz dla typu enum wybrać inne typy liczbowe pod warunkiem , że reprezentują one liczby całkowite. Czyli do dyspozycji mamy typy : byte, sbyte, short, ushort, int, uint, long, ulong.

Kolejne zastrzeżenie jest takie , że wartości bądź liczba wartości w enum nie może być większa niż zakres danego typu. Dla przykładu dla typu byte mogę przechowywać 256 wartości licząc z zerem.

enum KsztaltChmury : byte 
{
    Pierzasta,
    Warstwowa,
    Klebiaste
}

Po co to wszystko. Aby oszczędzać pamięć . Raczej jako programista nie stworzysz typu wyliczeniowego, który może przechowywać aż 2147483647 nie licząc wartości ujemnych.

Użyteczność typów wyliczeniowych

Powiedzmy , że chce tworzyć obiekt, który będzie przedstawiać chmurę. Każda chmura może być podzielona na odpowiednie typy.Wikipedia na temat chmur http://pl.wikipedia.org/wiki/Chmura

Chmury można podzielić na różne sposoby:

  • ze względu na wysokość występowania na :
    • chmury wysokie,
    • chmury średnie,
    • chmury niskie,
  • ze względu na kształt na:
    • chmury pierzaste,
    • chmury warstwowe,
    • chmury kłębiaste.
  • ze względu na budowę wewnętrzną:
    • chmury o rozciągłości poziomej,
    • chmury rozbudowane w pionie
  • ze względu na sposób powstania:
    • chmury falowe
    • chmury konwekcyjne
    • chmury frontowe

Teraz jak taką zależność w kodzie wykazać. Za pomocą zmiennych string byłoby to bolesne. Ponieważ do zmiennej string mogę umieścić jakąkolwiek wartość. No i oczywiście byłaby różnica pomiędzy łańcuchem “pierzasta” , a “Pierzasta”, chociaż programiście chodziło o to samo.

class ZlaChmura 
{
    public string KsztaltChmury;
    //....tak dalej 
}

Teraz jak mogę wyrazić typy chmur jak nie za pomocą typu wyliczeniowego.

class Chmura 
{
    public KsztaltChmury ksztalt;
    public WysokoscChmury wysokosc;
    public BudowaWewnetrznaChmury budowa;
    public SposobPowstaniaChmury powstanie;
}

enum KsztaltChmury : byte 
{
    Pierzasta,
    Warstwowa,
    Klebiaste
}

enum WysokoscChmury 
{
    wysokie,
    średnie,
    niskie
}

enum BudowaWewnetrznaChmury 
{
    pozioma,
    pionowa
}

enum SposobPowstaniaChmury 
{
    falowe,
    konwekcyjne,
    frontowe
}

A i w tym przykładzie możesz zauważyć pewną nieścisłość. Jak enum może wyrazić , że chmura jest np. pierzasto-kłębiasta. Co, jeśli istnieje niesamowita ilość kombinacji wartości. Np. mam typ wyliczeniowy dni tygodnia i chcę aby użytkownik mógł wybrać kombinacje każdego dnia z  każdym dniem.

Na tę problematykę poświęcę poświeciłem oddzielny post. Tak jest to wykonalne w C#. W każdym wypadku typy wyliczeniowe stałyby się trochę bezużyteczne, gdyby tego nie potrafiły.

Tyle o typie wyliczeniowym

W następnym wpisie struktury w C#. Wpis będzie dość krótki