C# – Różnice pomiędzy typem wartościowym, a referencyjnym

Loading Likes...

 

Słowem wstępu..

W języku C# mamy 4 kategorie typów:
– typy wartościowe
– typy referencyjne
– parametry typów generycznych
– typy wskaźnikowe

Jak pewnie się domyślasz, w tym wpisie poznasz różnicę pomiędzy dwoma pierwszymi.

Dlaczego warto znać te różnicę? Przede wszystkim jest to częste pytanie rekrutacyjne, na które warto się przygotować. Nie jest to nic skomplikowanego i tym bardziej warto kojarzyć te pojęcia. Nie jest to też wiedza, którą będziesz posługiwał się każdego dnia. Powiedziałbym, że jest to taki detal, który warto mieć “z tyłu głowy”. 🙂

Zaczynajmy!

Co musisz zapamiętać?

Do typów wartościowych zalicza się większość typów wbudowanych czyli:
– wszystkie liczbowe (int, decimal, double itd.)
char i bool
– oraz struct i enum

Do typów referencyjnych zalicza się:
– wszystkie klasy,
tablice
delegacje oraz interfejsy
string

Co jest fundamentalną różnicą między tymi kategoriami typów? Czyli czym się różnią typy wartościowe od referencyjnych?

Różnica dotyczy sposobu przechowywania ich wartości w pamięci. Zawartością zmiennej lub stałej typu wartościowego jest po prostu jedna wartość, np. dla typu int są 32 bity danych. Natomiast typy referencyjne składają się z dwóch części: obiektu i referencji – odniesienia do obiektu zawierającego wartość.

W pamięci typy wartościowe trafiają w sposób uporządkowany na stos (z ang. Stack), natomiast typy referencyjne trafiają na stertę (z ang. Heap), czyli tam gdzie jest to możliwe.

Bardzo ważne jest, aby wiedzieć, jaka jest jeszcze inna ciekawa różnica pomiędzy tymi typami. Istnieje też wyjątek od tej reguły, o którym wspomnę niżej.

Przypisywanie wartości niesie za sobą różne konsekwencje.

Przykład – dla typów wartościowych
Przypisanie wartości powoduje tylko jego skopiowanie

Jak zauważyłeś nie została zmodyfikowana zmienna “b”, czyli przypisanie “int b = a”, i aktualizacja zmiennej “a”, nie spowodowała zmiany wartości zmiennej “b”.

Teraz jak to się ma dla typów referencyjnych?

Stwórzmy sobie klasę, która będzie naszym typem referencyjnym.

Jak pokazał powyższy przykład, przypisanie obiektu “p1” do obiektu “p2” spowodowało, że utworzyła się referencja – czyli wskazanie na konkretną wartość w pamięci. Dlatego też każda modyfikacja obiektu “p1” będzie widoczna w obiekcie “p2”

Proste i logiczne. Natomiast, jest pewien wyjątek. Typ string jest typem referencyjnym, natomiast przypisanie działa jakby był typem wartościowym.
Zobacz przykład.

Dlaczego tak się dzieje? Szczerze mówiąc, szukałem odpowiedzi na ten temat w internecie i większość odpowiedzi wskazywała na to, że typ string może mieć bardzo dużą wartość, i po prostu musi być przechowywany na stercie (z ang. Heap). Dlatego, też jest typem referencyjnym, a nie wartościowym.

Czy zawsze typ wartościowy trafi na stos?

Takie pytanie zadał mi mój kolega, który przeczytał sobie ten wpis. Jest to bardzo ciekawe pytanie, ponieważ odpowiedź brzmi NIE, np. gdy mamy klasę, która posiada w sobie własność np. typu int, taka własność trafi wówczas na stertę. 🙂

You May Also Like

About the Author: Jerzy Kołakowski

Pasjonat informatyki, bloger. Full-stack Developer Technologie:
  • ASP.NET MVC
  • ASP.NET CORE
  • Angular 2+

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Facebook