C#,  Programowanie

Pudełkowanie (boxing) oraz odpakowywanie (unboxing) w języku C#

Nadszedł czas na wpis, do którego został stworzony ten blog, czyli na coś związanego z programowaniem. Na start opisze tutaj, czym jest mechanizm opakowania (lub pudełkowania) w C#. Zapraszam do czytania.

 

W języku C# wszystkie klasy dziedziczą po System.Object, klasie która jest położona najwyżej w hierarchii dziedziczenia. Za sprawą polimorfizmu, jednego z fundamentalnych założeń programowania zorientowanego obiektowo, można potraktować każdy obiekt dowolnej klasy właśnie jako typ object. Ponieważ nasz utworzony byt w uogólnieniu jest też object-em (bo po nim zawsze dziedziczy). Warto tutaj zaznaczyć, że object jest tym samym, co klasa System.Object.

 

MyClass myObject = new MyClass();
object obj = myObject;

 

Co jednak, gdy chcielibyśmy w taki sam sposób zamienić podstawowy typ, np. int na typ object. Int jest typem wartościowym, a object typem referencyjnym, zatem istnieje pomiędzy nimi pewna różnica. Czy istnieje możliwość na wykonanie takiej operacji? Tak, istnieje i nazywa się opakowywaniem.

 

Opakowanie lub pudełkowanie (ang. boxing) to konwersja zmiennej typu wartościowego (np. int, double lub bool) na typ object.

 

Rozpakowanie lub odpakowanie (ang. unboxing) to proces odwrotny do czynności opakowania. Pozwala on na przekonwertowanej zapakowanej już wartości, z powrotem na typ wartościowy.

 

Przyjrzyjmy się w praktyce jak się to robi, jest to bardzo proste.

 

//inicjalizowanie zmiennej
int i = 14;
//opakowanie zmiennej
object obj = i;

 
Po prostu wystarczy przypisać zmienną do typu object. Zachodzi tutaj konwersja niejawna, o której będzie również w innym wpisie. Z grubsza chodzi w niej o to, że nie rzutujemy zmienną i na typ object, czyli nie zmieniamy typu przed przypisaniem go do obiektu object.

To było z górki, teraz znacznie trudniejsza proces. Musimy odpakować to z powrotem, a to wymaga więcej! Zobaczmy.

 

//inicjalizowanie zmiennej
int i = 14;
//opakowanie zmiennej 
object obj = i;
//odpakowanie wartości do innej zmiennej tego samego typu
int j = (int)obj;

 

Cała różnica polega na tym, że tutaj musimy podczas konwersji użyć rzutowania (konwersja jawna, wskazujemy czym ma być nasz obiekt). Dzieje się to dlatego, że typ object jest typem dla wszystkiego i nigdy nie wiadomo co siedzi w środku.

Ale uważajcie na pułapkę, nie możemy rozpakować wartości o innym typie niż ten, który zapakowaliśmy. Nawet, jeżeli ten typ mieści się w innym (co znaczy, że nie utracił by wartości). Więc skoro to działa:

 

//inicjalizacja zmiennej
int i = 14;
//opakowanie zmiennej
object obj = i;
//rzutowanie jawne typu double na int (tak, mogło by być też niejawne)
double j = (double)i;

 

To niestety to nie zadziała:

 

 
//inicjalizacja zmiennej
int i = 14;
//opakowanie zmiennej object 
obj = i;
//odpakowanie dla innego typu niż początkowo był zapakowany
double j = (double)obj;

 

 

Nie możemy rozpakować obj, bo przed zapakowaniem był on int-em, chociaż bez problemu możemy przypisać zmienną int do double.

 

A teraz wisienka. Gdzie to się stosuje?

Ciężko było przypomnieć sobie rzeczywisty powód na wykorzystywanie tych mechanizmów. Proces o którym tutaj napisałem nie jest wydajny, wiec nie zaleca się go stosować. Jednak czasami bywają sytuacje, kiedy skorzystać z niego trzeba. W przeszłości były stosowane do chociażby kolekcji. Stare kolekcje, takie jak ArrayList przechowywało dane typu object. Jeżeli chcieliśmy przypisać im wartość typu podstawowego, musieliśmy skorzystać z pudełkowania. Jeśli natomiast chcieliśmy te dane pobrać, a wiedzieliśmy, że jest tam taki typ, trzeba by było je odpakować. Teraz zostało to zastąpione typem generycznym o którym w przyszłości też chce napisać.

Trzeba jednak mieć na uwadze, że w starszych systemach ten rodzaj kolekcji może być nadal wykorzystywany.

 

int i = 14;
ArrayList list = new ArrayList();
//pakowanie
list.Add(i);
//odpakowanie
int j = (int)list[0];

 

Drugi przykład to metody, których parametrem jest object, a do których chcielibyśmy wstawić typ wartościowy.

 

Podsumowując, proces ten jest intuicyjny, właściwie nie różni się niczym od polimorfizmu. Warto jednak wiedzieć z czym ma się do czynienia i wiedzieć, że nie jest to dobra praktyka. A czy wy mieliście styczność z pudełkowaniem, a może w innych sytuacjach? Komentujcie.

Ps. Usprawiedliwię się tutaj jeszcze, że z tym trudem w odpakowywaniu to sobie żartowałem. Żeby nikt mnie w komentarzach nie oskarżał o herezje.

 

Social media & sharing icons powered by UltimatelySocial