Esercizio - Scoprire i tipi di riferimento
- 8 minuti
I tipi riferimento includono matrici, classi e stringhe. Per quanto riguarda le modalità di archiviazione dei valori durante l'esecuzione dell'applicazione, i tipi riferimento vengono trattati in modo diverso dai tipi valore.
In questo esercizio verranno illustrate le differenze tra i tipi riferimento e i tipi valore e come usare l'operatore new per associare una variabile a un valore nella memoria del computer.
Differenze tra tipi riferimento e tipi valore
Una variabile di tipo valore archivia i valori direttamente in un'area di archiviazione denominata stack. Lo stack è la memoria allocata al codice attualmente in esecuzione nella CPU (definita anche stack frame o frame di attivazione). Al termine dell'esecuzione dello stack frame, i valori nello stack vengono rimossi.
Una variabile di tipo riferimento archivia i valori in un'area della memoria separata chiamata heap. L'heap è un'area della memoria condivisa tra più applicazioni in esecuzione contemporaneamente nel sistema operativo. Il runtime .NET comunica con il sistema operativo per determinare quali indirizzi di memoria sono disponibili e richiede un indirizzo in cui poter archiviare il valore. Il runtime .NET archivia il valore e quindi restituisce l'indirizzo di memoria alla variabile. Quando il codice usa la variabile, il runtime .NET cerca facilmente l'indirizzo archiviato nella variabile e recupera il valore archiviato.
Scriviamo un codice che illustri in modo più chiaro questi concetti.
Passaggio 2 - Definire una variabile di tipo riferimento
Eliminare o usare l'operatore di commento riga
//per impostare come commento tutto il codice degli esercizi precedenti.Aggiornare il codice nell'editor di Visual Studio Code come indicato di seguito:
int[] data;Il codice seguente definisce una variabile che può contenere un valore di tipo matrice
int.A questo punto,
dataè semplicemente una variabile che può contenere un riferimento, o piuttosto un indirizzo di memoria di un valore nell'heap. Poiché non punta a un indirizzo di memoria, viene chiamata riferimento Null.Passaggio 3 - Creare un'istanza della matrice
intusando la parola chiavenewAggiornare il codice nell'editor di Visual Studio Code per creare e assegnare una nuova istanza di
intmatrice usando il codice seguente:int[] data; data = new int[3];La parola chiave
newindica al runtime .NET di creare un'istanza della matriceinte quindi di coordinarla con il sistema operativo per archiviarla in memoria. Il runtime .NET è conforme e restituisce un indirizzo di memoria della nuova matriceint. L'indirizzo di memoria viene infine archiviato nei dati della variabile. Per impostazione predefinita, gli elementi della matriceinthanno valore0perché si tratta del valore predefinito diint.Passaggio 4 - Modificare l'esempio di codice per eseguire entrambe le operazioni in una singola riga di codice
Le due righe di codice del passaggio 3 vengono in genere abbreviate in una sola riga di codice sia per dichiarare la variabile che per creare una nuova istanza della matrice
int. Modificare il codice del passaggio 3 sostituendolo con il seguente.int[] data = new int[3];Anche non vengono restituiti output da esaminare, lo scopo dell'esercizio era quello di chiarire la correlazione tra la sintassi C# e i passaggi del processo per l'uso dei tipi riferimento.
Quali sono le differenze del tipo di dati stringa C#?
Il tipo di dati string è anche un tipo riferimento. Ci si potrebbe chiedere perché un operatore new non è stato usato durante la dichiarazione di una stringa. Si tratta semplicemente di una comodità offerta dai progettisti di C#. Poiché il tipo di dati string viene usato molto frequentemente, è possibile usare questo formato:
string shortenedString = "Hello World!";
Console.WriteLine(shortenedString);
Dietro le quinte, tuttavia, viene creata e inizializzata una nuova istanza di System.String con "Hello World!".
Problemi pratici relativi all'uso di valori e tipi di riferimento
-
Tipo valore (int): In questo esempio
val_Aeval_Bsono tipi di valore interi.
int val_A = 2;
int val_B = val_A;
val_B = 5;
Console.WriteLine("--Value Types--");
Console.WriteLine($"val_A: {val_A}");
Console.WriteLine($"val_B: {val_B}");
Verrà visualizzato l'output seguente:
--Value Types--
val_A: 2
val_B: 5
Quando viene eseguito val_B = val_A, il valore di val_A viene copiato e archiviato in val_B. Quindi, quando val_B viene modificato, val_A rimane invariato.
-
Tipo riferimento (array): In questo esempio
ref_Aeref_Bsono tipi di riferimento matrice.
int[] ref_A= new int[1];
ref_A[0] = 2;
int[] ref_B = ref_A;
ref_B[0] = 5;
Console.WriteLine("--Reference Types--");
Console.WriteLine($"ref_A[0]: {ref_A[0]}");
Console.WriteLine($"ref_B[0]: {ref_B[0]}");
Verrà visualizzato l'output seguente:
--Reference Types--
ref_A[0]: 5
ref_B[0]: 5
Quando viene eseguito ref_B = ref_A, ref_B punta alla stessa posizione di memoria di ref_A. Quindi, quando ref_B[0] viene modificato, ref_A[0] cambia anche perché entrambi puntano alla stessa posizione di memoria. Si tratta di una differenza fondamentale tra i tipi valore e i tipi riferimento.
Riepilogo
- I tipi valore possono contenere valori più piccoli e vengono archiviati nello stack. I tipi riferimento possono contenere valori grandi. Una nuova istanza di un tipo riferimento viene creata usando l'operatore
new. Le variabili di tipo riferimento contengono un riferimento (l'indirizzo di memoria) al valore effettivo archiviato nell'heap. - I tipi riferimento includono matrici, stringhe e classi.