CodeGym /Corsi /C# SELF /Introduzione ai Nullable Reference Types

Introduzione ai Nullable Reference Types

C# SELF
Livello 14 , Lezione 1
Disponibile

1. Il problema di NullReferenceException

Praticamente ogni programmatore alle prime armi (e non solo) in C# si è imbattuto almeno una volta in questo messaggio spaventoso:


System.NullReferenceException: Object reference not set to an instance of an object.

Ecco un classico esempio:

string hello = null;
Console.WriteLine(hello.Length); // BAM! NullReferenceException

Il senso è semplice: stai cercando di accedere a un oggetto che non esiste. Cioè la variabile punta a null — uno spazio vuoto invece di un oggetto.

Perché è facile commettere questo errore?

Perché la maggior parte dei tipi reference in C# storicamente potevano assumere il valore null. Gli sviluppatori spesso si dimenticavano di controllare che la variabile puntasse davvero a un oggetto, e di conseguenza beccavano la famosa NullReferenceException.

Se uno sviluppatore ricevesse un dollaro per ogni NullReferenceException, avrebbe già scritto il suo sistema operativo.

Perché è un problema?

Prima abbiamo imparato a fare in modo che i valori tipo int? o double? potessero essere null — per i casi in cui serve indicare esplicitamente "assenza di valore" (ad esempio, un campo nel database può essere vuoto).

Ma i tipi reference (tipo string, qualsiasi classe, array ecc.) potevano sempre essere null. È stato così fin dalla nascita di C#. Comodo, sì, ma anche pericoloso — perché il linguaggio non ci obbligava a pensare: "Questa reference può essere vuota?"

2. Evoluzione: Nullable Reference Types (NRT)

5 anni fa è arrivata una novità che ha rivoluzionato il modo di combattere le NullReferenceException — i Nullable Reference Types (NRT).

string s = "hello";   // not-nullable reference
string? maybe = null; // nullable reference
Differenza tra reference not-nullable e nullable

L'idea principale:

  • Separare in modo rigoroso le variabili reference che non possono mai essere null da quelle che invece possono essere vuote.
  • Aiutare lo sviluppatore a vedere i potenziali problemi con null già in fase di compilazione, non a runtime (quando ormai è troppo tardi).

Nelle nuove versioni di C# è cambiato l'approccio alla dichiarazione delle variabili reference: di default non puoi assegnare null, a meno che tu non lo permetta esplicitamente.

Basta un solo simbolo ? e il significato della variabile cambia subito!

3. Attivare i Nullable Reference Types

Di default questa sintassi rigorosa è disattivata nella maggior parte dei progetti, per non rompere il vecchio codice. Ma i template moderni di progetto in Visual Studio, Rider e .NET CLI già creano progetti con NRT attivi — o almeno ti consigliano caldamente di farlo.

Per sapere se gli NRT sono attivi nel tuo progetto, cerca nel file .csproj questa riga:

<Nullable>enable</Nullable>
Attivare NRT nel progetto

Se questa riga non c'è, puoi aggiungerla a mano — è sicuro.

Come influisce sul codice?

  • Se gli NRT sono disattivati (vecchio comportamento): string s = null; — nessun errore, tutto ok.
  • Se sono attivi: il compilatore si lamenta se provi a mettere null dove non dovrebbe esserci null.

4. Esempi con NRT

Esempio semplice


#nullable enable // Questa riga attiva il controllo NRT per questo file

string notNullable = "Ciao";
string notNullable2 = null; // ERRORE di compilazione!
string? nullableString = null; // Tutto ok, abbiamo permesso esplicitamente null
Esempio di controllo rigoroso su null

Nella prima riga abbiamo dichiarato una stringa che deve sempre puntare a un oggetto reale.
Nella terza — una stringa che può essere null.

Controllo su null

void PrintLength(string? s)
{
    // Il compilatore si lamenterà: "E se s == null?"
    Console.WriteLine(s.Length); 
    
    // Così invece va bene
    if (s != null)
    {
        Console.WriteLine(s.Length); 
    }
}

Il compilatore ora ti aiuta a non dimenticare i controlli!

Avvisi del compilatore

Se ignori l'avviso e provi comunque ad accedere a una variabile nullable senza controllo — riceverai un nuovo (e molto utile!) avviso dal compilatore. Non è un errore (il programma si compila lo stesso), ma la "lampadina" gialla ti suggerisce: "Sei sicuro, amico?"

Confrontiamo le modalità:

Tipo C# Può essere null? Modalità Legacy (prima di NRT) Modalità NRT (#nullable enable)
int No No No
int?
string No (sempre possibile) No (di default non si può)
string? No

5. Consigli: come e perché usare gli NRT

  • Meno bug: Meno crash improvvisi per colpa di null, più felicità per dev e utenti.
  • Codice più chiaro: Si vede subito cosa può essere vuoto e cosa deve essere sempre valorizzato.
  • Aiuto dal compilatore: Ammettilo — ci sta davvero aiutando! Gli avvisi NRT sono una fonte preziosa di info su possibili errori.

Dove è indispensabile

  • Nei progetti grandi, dove tante persone lavorano sullo stesso codice.
  • Negli API e nelle librerie pubbliche — per spiegare agli altri cosa possono e non possono fare.
  • Dove serve affidabilità (tipo app bancarie, sistemi medici ecc.)

6. Errori tipici e trappole

  • "Hai dimenticato il ?"
    Assegni null a una stringa normale (string s = null;) — e il compilatore si lamenta, perché ora di default una stringa normale non può essere null.
  • "Hai esagerato con il ?"
    Fai tutte le variabili string? solo per non far arrabbiare il compilatore. Ma il senso è annotare con attenzione dove davvero può esserci un valore vuoto.
  • "Hai frainteso l'avviso"
    Ignori l'avviso e poi becchi una NullReferenceException dove pensavi che il compilatore ti avrebbe protetto.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION