Conversia tipurilor de date de bază
Atunci când discutăm despre tipurile de date, am menționat ce valori poate avea un anumit tip și cât spațiu de memorie poate ocupa. În tema anterioară am discutat despre operațiile aritmetice. Acum vom aplica operația de adunare la date de tipuri diferite:
byte a = 4;
int b = a + 70;
Rezultatul acestei operații este numărul 74, așa cum era de așteptat.
Dar acum vom încerca să aplicăm adunarea la două obiecte de tip byte:
byte a = 4;
byte b = a + 70; // eroare
Aici s-a schimbat doar tipul variabilei care primește rezultatul adunării - de la int la byte. Totuși, când încercăm să compilăm programul, vom primi o eroare la compilare. Dacă lucrăm în Visual Studio, mediul va sublinia a doua linie cu o linie ondulată roșie, indicând că există o eroare.
De ce apare eroarea?
În operațiile aritmetice trebuie să luăm în considerare intervalul de valori pe care le poate stoca un anumit tip. În acest caz, numărul 74, pe care ne așteptăm să-l obținem, se încadrează în intervalul de valori pentru tipul byte, totuși obținem o eroare.
Motivul este că operația de adunare (și scădere) returnează o valoare de tip int dacă în operație sunt implicate tipuri de date întregi cu dimensiuni mai mici sau egale cu int (adică tipuri byte, short, int).
Prin urmare, rezultatul operației a + 70 va fi un obiect care ocupă 4 octeți în memorie. Apoi încercăm să atribuim acest obiect variabilei b, care este de tip byte și ocupă 1 octet în memorie.
Pentru a rezolva această problemă, trebuie să aplicăm operația de conversie a tipurilor. Operația de conversie a tipurilor implică specificarea în paranteze a tipului la care trebuie convertită valoarea:
(byte)(valoare_pentru_conversie);
Să modificăm exemplul anterior, aplicând operația de conversie a tipurilor:
byte a = 4;
byte b = (byte)(a + 70);
Conversii de extindere și restrângere
Conversiile pot fi de extindere (widening) și de restrângere (narrowing). Conversiile de extindere măresc dimensiunea obiectului în memorie. De exemplu:
byte a = 4; // 0000100
ushort b = a; // 0000000000000100
În acest caz, variabilei de tip ushort i se atribuie o valoare de tip byte. Tipul byte ocupă 1 octet (8 biți), iar valoarea variabilei a în formă binară poate fi reprezentată astfel:
00000100
Valoarea de tip ushort ocupă 2 octeți (16 biți). La atribuirea valorii variabilei b, valoarea variabilei a este extinsă la 2 octeți:
0000000000000100
Conversii de restrângere
Conversiile de restrângere reduc dimensiunea valorii la un tip cu o dimensiune mai mică. În al doilea exemplu din articol am avut de-a face cu conversii de restrângere:
ushort a = 4;
byte b = (byte)a;
Aici variabilei b, care ocupă 8 biți, i se atribuie o valoare ushort, care ocupă 16 biți. Astfel, din:
0000000000000100
obținem:
00000100
Conversii implicite și explicite
Conversii implicite
În cazul conversiilor de extindere, compilatorul efectuează automat conversiile, adică acestea sunt conversii implicite (implicit conversion). Aceste conversii nu cauzează probleme. Totuși, este important să înțelegem mecanismul general al acestor conversii.
Dacă se efectuează o conversie de la un tip fără semn cu dimensiuni mai mici la un tip fără semn cu dimensiuni mai mari, se adaugă biți suplimentari cu valoarea 0. Aceasta se numește extindere cu zerouri (zero extension).
byte a = 4; // 0000100
ushort b = a; // 0000000000000100
Dacă se efectuează o conversie la un tip cu semn, reprezentarea binară este completată cu zerouri dacă numărul este pozitiv și cu unități dacă numărul este negativ. Ultimul bit al numărului conține bitul de semn - 0 pentru numere pozitive și 1 pentru numere negative. La extindere, bitul de semn este copiat în biții adăugați.
Conversie a unui număr pozitiv:
sbyte a = 4; // 0000100
short b = a; // 0000000000000100
Conversie a unui număr negativ:
sbyte a = -4; // 1111100
short b = a; // 1111111111111100
Conversii explicite
La conversiile explicite (explicit conversion) trebuie să aplicăm manual operația de conversie (operația ()). Esența operației de conversie constă în specificarea în paranteze a tipului la care trebuie convertită valoarea:
int a = 4;
int b = 6;
byte c = (byte)(a + b);
Conversiile de extindere de la tipuri cu dimensiuni mai mici la tipuri cu dimensiuni mai mari sunt realizate implicit de către compilator. Acestea pot fi următoarele lanțuri de conversii:
- byte -> short -> int -> long -> decimal
- int -> double
- short -> float -> double
- char -> int
Toate conversiile automate sigure pot fi descrise în următorul tabel:


În celelalte cazuri, trebuie să utilizăm conversii explicite.
De asemenea, este de remarcat faptul că, deși atât double cât și decimal pot stoca date fracționare, iar decimal are o precizie mai mare decât double, totuși valoarea double trebuie convertită explicit la tipul decimal:
double a = 4.0;
decimal b = (decimal)a;
Pierderea preciziei datelor
Să analizăm o altă situație, de exemplu, următoarea:
int a = 33;
int b = 600;
byte c = (byte)(a + b);
Console.WriteLine(c); // 121
Rezultatul va fi numărul 121, deoarece numărul 633 nu se încadrează în intervalul permis pentru tipul byte, iar biții superiori vor fi trunchiați. Astfel, obținem numărul 121. Prin urmare, la conversii trebuie să ținem cont de acest lucru. În acest caz, putem fie să folosim astfel de numere a și b, încât suma lor să fie mai mică sau egală cu 255, fie să alegem un alt tip de date în loc de byte, de exemplu, int.