Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Aggiornamento: novembre 2007
Diversamente da alcuni linguaggi di programmazione, in C# sono disponibili due varietà di tipi di dati: valore e riferimento. È importante stabilire se le prestazioni dell'applicazione sono importanti o se invece si ritiene importante la modalità di gestione di dati e memoria in C#.
Quando una variabile viene dichiarata tramite uno dei tipi di dati incorporati di base o una struttura definita dall'utente, rappresenta un tipo di valore. Un'eccezione è rappresentata dal tipo di dati string, che è un tipo di riferimento.
Un tipo di valore archivia il proprio contenuto in memoria allocata sullo stack. In questo caso, il valore 42 viene ad esempio archiviato in un'area di memoria chiamata stack.
int x = 42;
Quando la variabile x esce dall'ambito di validità poiché è stata completata l'esecuzione del metodo in cui è stata definita, il valore viene eliminato dallo stack.
L'utilizzo dello stack è efficace, ma la durata limitata dei tipi di valore li rende meno adatti per la condivisione di dati tra classi diverse.
Al contrario, un tipo di riferimento, come un'istanza di una classe o una matrice, viene allocato in un'area diversa di memoria denominata heap. Nell'esempio riportato di seguito lo spazio necessario per i dieci valori integer che costituiscono la matrice viene allocato nell'heap.
int[] numbers = new int[10];
Questo tipo di memoria non viene restituito all'heap al completamento di un metodo, ma viene recuperata soltanto quando il sistema di Garbage Collection di C# stabilisce che non è più necessaria. La dichiarazione dei tipi di riferimento comporta un sovraccarico maggiore, ma questi tipi presentano il vantaggio di essere accessibili da altre classi.
Boxing e unboxing
Boxing è il nome assegnato al processo mediante il quale un tipo di valore viene convertito in un tipo di riferimento. Quando si esegue il boxing di una variabile, viene creata una variabile di riferimento che punta a una nuova copia nell'heap. La variabile di riferimento è un oggetto e, di conseguenza, può utilizzare tutti i metodi che vengono ereditati da ogni oggetto, ad esempio ToString(). Questa operazione è descritta nel codice riportato di seguito:
int i = 67; // i is a value type
object o = i; // i is boxed
System.Console.WriteLine(i.ToString()); // i is boxed
Il processo di unboxing si verifica quando vengono utilizzate classi progettate per l'utilizzo con oggetti: ad esempio mediante una classe ArrayList per archiviare valori integer. Quando un valore integer viene archiviato in una classe ArrayList, viene eseguito il processo di boxing. Quando un valore integer viene recuperato, è necessario eseguirne l'unboxing.
System.Collections.ArrayList list =
new System.Collections.ArrayList(); // list is a reference type
int n = 67; // n is a value type
list.Add(n); // n is boxed
n = (int)list[0]; // list[0] is unboxed
Problemi relativi alle prestazioni
Di seguito viene presentata un'analisi più approfondita sull'argomento. Quando i dati vengono passati nei metodi come parametri di tipi di valore, viene creata una copia di ciascun parametro nello stack. È ovvio che se il parametro in questione è un tipo di dati di grandi dimensioni, come una struttura definita dall'utente con molti elementi, o se il metodo viene eseguito molte volte, le prestazioni possano esserne influenzate.
In queste situazioni può essere preferibile passare un riferimento al tipo, utilizzando la parola chiave ref. Questa operazione è l'equivalente in C# della tecnica di C++ di passare un puntatore a una variabile in una funzione. Come nella versione C++, il metodo è in grado di modificare il contenuto della variabile, che potrebbe non essere sempre sicura. Per il programmatore si pone la necessità di scegliere tra protezione e prestazioni.
int AddTen(int number) // parameter is passed by value
{
return number + 10;
}
void AddTen(ref int number) // parameter is passed by reference
{
number += 10;
}
La parola chiave out è simile alla parola chiave ref, ma indica al compilatore che il metodo deve assegnare un valore al parametro, altrimenti si verificherà un errore di compilazione.
void SetToTen(out int number)
{
// If this line is not present, the code will not compile.
number = 10;
}
Vedere anche
Concetti
Nozioni di base del linguaggio C#
Tipi di dati incorporati (Visual C# Express)
Matrici e insiemi (Visual C# Express)
Riferimenti
Tipi di valore (Riferimenti per C#)