MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Supraincărcarea operațiilor de conversie a tipurilor

În tema anterioară am discutat despre supraincărcarea operatorilor. Aceasta este strâns legată de supraincărcarea operatorilor de conversie a tipurilor.

Anterior, am discutat despre conversiile explicite și implicite ale tipurilor primitive. De exemplu:

int x = 50;
byte y = (byte)x; // conversie explicită de la int la byte
int z = y;  // conversie implicită de la byte la int

Ar fi util să putem defini logica de conversie a unui tip în altul. Prin supraincărcarea operatorilor, putem face acest lucru. Pentru aceasta, în clasă se definește o metodă cu următoarea formă:

public static implicit|explicit operator Tip_în_care_să_convertim(tip_de_origine param)
{
   // logica de conversie
}

După modificatorii public static urmează cuvântul cheie explicit (dacă conversia este explicită, adică este necesară operația de casting) sau implicit (dacă conversia este implicită). Apoi urmează cuvântul cheie operator și tipul returnat, în care trebuie convertit obiectul. În paranteze, ca parametru, se transmite obiectul care trebuie convertit.

De exemplu, să presupunem că avem următoarea clasă Counter, care reprezintă un contor-cronometru și care stochează numărul de secunde în proprietatea Seconds:

class Counter
{
   public int Seconds { get; set; }

   public static implicit operator Counter(int x)
   {
       return new Counter { Seconds = x };
   }
   public static explicit operator int(Counter counter)
   {
       return counter.Seconds;
   }
}

Primul operator convertește un număr - obiect de tip int la tipul Counter. Logica sa este simplă - se creează un nou obiect Counter, căruia i se setează proprietatea Seconds.

Al doilea operator convertește obiectul Counter la tipul int, adică obține un număr din Counter.

Aplicarea operatorilor de conversie în program:

Counter counter1 = new Counter { Seconds = 23 };

int x = (int)counter1;
Console.WriteLine(x);   // 23

Counter counter2 = x;
Console.WriteLine(counter2.Seconds);  // 23

Deoarece operația de conversie din Counter în int este definită cu cuvântul cheie explicit, adică ca o conversie explicită, în acest caz este necesară operația de casting:

int x = (int)counter1;

În cazul operației de conversie de la int la Counter nu este nevoie de nimic similar, deoarece această operație este definită cu cuvântul cheie implicit, adică ca o conversie implicită. Ce operații de conversie să fie făcute explicite și care implicite este decizia dezvoltatorului.

Trebuie avut în vedere că operatorul de conversie a tipurilor trebuie să convertească din tipul sau în tipul în care acest operator este definit. Adică operatorul de conversie definit în tipul Counter trebuie să accepte ca parametru un obiect de tip Counter sau să returneze un obiect de tip Counter.

Să examinăm și conversii mai complexe, de exemplu, dintr-un tip compus într-alt tip compus. Să presupunem că avem și clasa Timer:

class Timer
{
   public int Hours { get; set; }
   public int Minutes { get; set; }
   public int Seconds { get; set; }
}
class Counter
{
   public int Seconds { get; set; }

   public static implicit operator Counter(int x)
   {
       return new Counter { Seconds = x };
   }
   public static explicit operator int(Counter counter)
   {
       return counter.Seconds;
   }
   public static explicit operator Counter(Timer timer)
   {
       int h = timer.Hours * 3600;
       int m = timer.Minutes * 60;
       return new Counter { Seconds = h + m + timer.Seconds };
   }
   public static implicit operator Timer(Counter counter)
   {
       int h = counter.Seconds / 3600;
       int m = (counter.Seconds % 3600) / 60;
       int s = counter.Seconds % 60;
       return new Timer { Hours = h, Minutes = m, Seconds = s };
   }
}

Clasa Timer reprezintă un cronometru care stochează orele, minutele și secundele. Clasa Counter reprezintă un contor-cronometru care stochează numărul de secunde.

Pornind de la aceasta, putem defini o anumită logică de conversie dintr-un tip în altul, adică obținerea din secunde în obiectul Counter a orelor, minutelor și secundelor în obiectul Timer. De exemplu, 3675 secunde înseamnă 1 oră, 1 minut și 15 secunde.

Aplicarea operațiilor de conversie:

Counter counter1 = new Counter { Seconds = 115 };

Timer timer = counter1;
Console.WriteLine($"{timer.Hours}:{timer.Minutes}:{timer.Seconds}"); // 0:1:55

Counter counter2 = (Counter)timer;
Console.WriteLine(counter2.Seconds);  //115
← Lecția anterioară Lecția următoare →