În C++, orice variabilă poate fi alocată pe stivă sau pe heap, în funcție de modul în care este declarată. În C#, distincția este mai rigidă și este determinată de tipul variabilei, nu de modul de alocare. Tipurile valoare (value types) sunt stocate direct pe stivă (sau inline în obiectul care le conține). Acestea includ toate tipurile numerice (int, double, float etc.), char, bool, enum și struct. Atunci când atribuiți o variabilă de tip valoare altei variabile, se face o copie a valorii.
Tipurile referință (reference types) sunt întotdeauna alocate pe heap, iar variabila stochează doar o referință (similar unui pointer) către obiectul propriu-zis. Acestea includ class, string, array-urile și object. La atribuire se copiază referința, nu obiectul.
// Tipuri valoare - se copiaza valoareainta=10;intb=a;// b este o copie independentab=20;// a ramane 10// Tipuri referinta - se copiaza referintaint[]arr1={1,2,3};int[]arr2=arr1;// arr2 refera acelasi array !arr2[0]=99;
Un concept important legat de tipurile valoare și referință este boxing și unboxing. Deoarece în C# toate tipurile derivă din System.Object, un tip valoare poate fi convertit implicit într-un object (boxing). Aceasta presupune alocarea pe heap și copierea valorii. Operația inversă (unboxing) extrage valoarea din obiectul de pe heap. Aceste operații sunt costisitoare și trebuie evitate în cod critic din punct de vedere al performanței.
intnumar=42;objectobj=numar;// boxing : valoarea se împachetează într-un objectintextras=(int)obj;// unboxing : se extrage valoarea dintr-un object// Aliasuri : int este de fapt System . Int32
Acest lucru poate fi contraintuitiv la început, deoarece în C++ tipurile primitive nu derivă dintr-un tip comun. În C#, toate tipurile, inclusiv cele primitive, derivă din System.Object , iar denumiri precum int sau float nu sunt nimic altceva decât alias-uri la clasele care implementează concret acele tipuri.