book-openEnumerații

Să presupunem că vrem să stocăm tipul unui film pe un bilet. Prima variantă care vine în minte este un string:

class Bilet
{
    public string TipFilm { get; set; }
}

Funcționează tehnic, dar nu oferă nicio garanție asupra valorilor acceptate. Orice cod din program poate scrie orice:

bilet.TipFilm = "Comedie";
bilet.TipFilm = "comedie";    // acelasi lucru? sau tip diferit?
bilet.TipFilm = "COMEDIE";    // si asta?
bilet.TipFilm = "komedye";    // greseala de tastare — compilatorul nu observa
bilet.TipFilm = "SF";         // tip care nu exista in sistemul nostru

Toate aceste atribuiri compilează fără erori. Niciuna nu este semnalată ca problemă. Bug-urile apar mai târziu, când codul încearcă să compare sau să proceseze valoarea și găsește ceva neașteptat — o literă mare în loc de mică, o greșeală de tastare, un tip care nu ar trebui să existe.

Rădăcina problemei este că string poate reprezenta orice, iar noi vrem să reprezentăm o mulțime finită și bine definită de valori. Avem nevoie de un tip care să exprime exact această constrângere.

Ce este o enumerație?

O enumerație este un tip care poate lua doar una dintre valorile declarate explicit. Se definește cu cuvântul cheie enum:

enum TipFilm
{
    Comedie,
    Actiune,
    Drama,
    Istoric
}

TipFilm este acum un tip de sine stătător, la fel ca int sau string. O variabilă de acest tip poate conține exclusiv una dintre cele patru valori declarate. Orice altceva este respins de compilator:

Greșelile de tipul "komedye" devin imposibile. Nu există niciun string de comparat, nicio capitalizare de verificat, nicio valoare surpriză de tratat. Compilatorul verifică la fiecare atribuire că valoarea aparține mulțimii definite.

Utilizarea enumerației în clasă

Proprietatea din clasa Bilet devine de tipul TipFilm în loc de string:

Atribuirea și citirea funcționează cu aceeași sintaxă ca orice altă proprietate:

Codul este explicit și fără ambiguitate. Nu mai trebuie să ne amintim formatul exact al stringului, nu există inconsistențe de capitalizare și nu există posibilitatea ca un tip inexistent să ajungă în sistem.

Enumerații în switch

Un caz de utilizare frecvent și natural pentru enumerații este instrucțiunea switch, unde dorim să tratăm diferit fiecare valoare posibilă. Enumerațiile se potrivesc perfect pentru acest pattern deoarece mulțimea cazurilor posibile este finită și cunoscută la compilare:

Dacă adăugăm ulterior o nouă valoare în enumerație (de exemplu SF), compilatorul însuși nu avertizează automat că avem un case lipsă în switch, dar IDE-ul o va semnala și este mult mai ușor să găsim toate locurile afectate decât dacă am fi folosit string-uri. Oricum suntem cu mult mai în control față de varianta bazată pe string.

Reprezentarea numerică internă

În memorie, o enumerație este stocată ca un număr întreg. Prin convenție, primul element are valoarea 0, al doilea 1 și așa mai departe, dacă nu specificăm altfel:

Putem atribui valori numerice explicite fiecărui element, ceea ce este util când enumerația trebuie să corespundă unor coduri dintr-o bază de date sau dintr-un protocol extern:

Conversia din număr în enumerație este posibilă, dar necesită un cast explicit. Aceasta poate eșua dacă numărul nu corespunde niciunei valori definite:

În exercițiul nostru nu avem nevoie de valori numerice explicite. Le menționăm deoarece sunt o sursă frecventă de confuzie atunci când enumerațiile sunt serializate sau stocate în baze de date. Valoarea numerică stocată trebuie să corespundă valorii din cod, inclusiv după refactorizări care reordonează elementele.

Conversia la string și din string

Când afișăm o valoare de tip enumerație sau o convertim la string, C# returnează automat numele valorii:

Conversia inversă (din string în enumerație) se face cu Enum.Parse:

Enum.Parse aruncă excepție dacă string-ul nu corespunde niciunei valori definite. Varianta mai sigură, care returnează false în loc să arunce excepție, este Enum.TryParse:

Enum.TryParse este de preferat ori de câte ori valoarea string provine dintr-o sursă externă (intrare de la utilizator, fișier, rețea) unde nu putem garanta că valoarea este validă.

Last updated