Własne konwersje Explicit i Implicit

W C# możemy tworzyć własne konwersji obiektów.  Przy użyciu słów kluczowych Explicit  Implicit możemy przeprowadzić konwersję typów referencyjnych na wartościowe i odwrotnie.

Na początek podstawy.

Konwersje Implicit nie wymagają żadnych dodatkowych słów kluczowych, ponieważ kompilator dopuszcza tylko takie konwersje, które są bezpieczne (czyli na przykład takich, w których nie ma utraty precyzji). Przykład  poniżej:

int i = 1234;
double d = i;

To jest konwersja Implicit.

Można również przeprowadzić konwersję typów wartościowych na typy bazowe. (każdy typ referencyjny  w C# dziedziczy po typie object).

StreamReader sr = new StreamReader("Plik.txt");

object o = sr;

IDisposable d = sr;

StreamReader dziedziczy po object więc konwersja jest możliwa.

StreamReader dziedziczy również po interfejsie IDisposable  więc i ta konwersja jest możliwa.


Konwersje Explicit czyli inaczej mówiąc Casting pozwalają na konwersję obiektów mimo tego, że taka konwersja może spowodować utratę precyzji lub po prostu danych. Jedną z różnic pomiędzy Explicit i Implicit jest to, że konwersje Explicit potrzebują odpowiedniej składni.  Poniżej przykład.

double x = 1234.7;
int y;
y = (int)x;

To jest konwersja Explicit. Wartość zmiennej będzie równa 1234.

Składania konwersji Explicit zmusza Nas do jawnego przedstawienia typu do którego wykonujemy konwersję (aby wykonać casting wystarczy przed zmienną w nawiasach wpisać typ do którego wykonujemy konwersję). Linikja 3.

Dla typów referencyjnych również istnieje możliwość wykonania konwersji typu Explicit. Przykład poniżej:

Object stream = new MemoryStream();

MemoryStream memoryStream = (MemoryStream)stream;

Klasa Object jest bardzo szeroka (każdy typ referencyjny  w C# dziedziczy po typie object) więc żeby wyciągnąć z obiektu Object tylko ten fragment, który chcemy musimy jawnie dać znać, że reszta Nas nie interesuje. W takim właśnie przypadku korzystamy z konwersji Explicit.


Teraz najważniejsze. W C# możemy tworzyć własne konwersje Explicit  Implicit.  To znaczy możemy oprogramować zachowanie się naszego obiektu podczas konwersji Explicit  lub Implicit. 

Poniżej prosty przykład jak stworzyć konwersję Explicit. Przykład służy tylko i wyłącznie demonstracji składni konwersji Explicit.

Wyobraźmy sobie dwa obiekty Portfel i Gotowka. Naszym zadaniem będzie wyciągnięcie Gotowki z Portfela przy użyciu konwersji.

class Portfel
{
 decimal gotowka;

 public Portfel(decimal gotowka)
 {
  this.gotowka = gotowka;
 }

 public static explicit operator Gotowka(Portfel bank)
 {
  return new Gotowka
  {
   Wartosc= bank.gotowka
  };
 }
}

class Gotowka
{
 public decimal Wartosc { get; set; }
}

Składnia jest dość intuicyjna. Po wyrażeniu “public static explicit operator ” wstawiamy typ na który będziemy wykonywać konwersję a jako argument podajemy obiekt do konwersji.

Działanie kodu widać poniżej:


Portfel portfel = new Portfel(12000.56M);

Gotowka gotowka = (Gotowka)portfel;

Konwersja Explicit potrzebuje dodatkowej składni czyli podania typu do którego wykonujemy konwersję w nawiasach przez zmienną.

Poniżej widać, że w obiekcie gotówka znajduje się wartość gotówki z portfela.

explit_1

Jeśli chodzi o składnie Implicit jest taka sama tylko z innym słowem kluczowym – “public static implicit operator Gotowka(Portfel bank)”

Osobiście nie spotkałem się z takimi rozwiązaniami w kodzie w prywatnych firmach finansowych w których pracowałem.

Dużą wadą takich rozwiązań jest słaba czytelność kodu. Nigdy tak do końca nie wiadomo co zostało poddane konwersji i jak ta konwersja przebiegła.  Podobnie zresztą jak w przypadku definiowania operatorów. Też ciężko uzasadnić przypadki mnożenia dwóch obiektów.

Mimo wszystko warto wiedzieć, że taka możliwość istnieje