CodeGym /Corsi /C# SELF /Tipi Nullable per tipi valore

Tipi Nullable per tipi valore

C# SELF
Livello 14 , Lezione 0
Disponibile

1. Introduzione

Immagina questa situazione. Stai salvando dati sui gatti nel codice. E vuoi, oltre ad esempio all'età del gatto, salvare anche stati tipo "nessun dato", "età sconosciuta". Potresti salvare 0, ma zero è un'età valida.

int age = 0; // Età del gatto. Ma cosa vuol dire 0? È un gattino o "sconosciuto"?

Il problema è che int accetta solo valori interi, e "nessun dato" tra i numeri interi non esiste. Se l'età fosse una stringa, potresti assegnare null. Ma con i numeri non funziona:

int age = null; // Errore! Non puoi assegnare null a una variabile di tipo int

Questo succede perché i tipi valore (struct come int, double, DateTime, bool) hanno sempre un valore. Non hanno uno stato "vuoto" (a differenza dei tipi reference, dove null è semplicemente l'assenza di un oggetto).

Esempio dalla vita reale:
Per aggirare questa limitazione, a volte i programmatori inventano valori "speciali": tipo -1 o int.MaxValue per "nessun valore". Ma è brutto, scomodo e rischioso: puoi confondere un valore reale con un segnaposto.

2. Tipo Nullable: un tipo che può essere "null"

Idea

E se permettessimo ai numeri normali (e a tutti i tipi valore) di contenere non solo un valore, ma anche null?
In C# questo si fa con una classe wrapper speciale: Nullable<T>. Questa classe può contenere o un valore di tipo T, oppure niente (cioè null).

Sintassi

int? age = null; // La variabile age può essere sia un numero che null
Dichiarazione di un tipo nullable usando ?

Il compilatore C#, quando vede questo codice, in realtà lo interpreta come:

Nullable<int> age = new Nullable<int>(); // La variabile age non contiene un valore

Oppure, se vuoi specificare un valore:

Nullable<int> age = new Nullable<int>(42); // age contiene il numero 42

Quindi, il punto di domanda trasforma qualsiasi tipo valore nella sua versione nullable:

  • int? (uguale a Nullable<int>)
  • double?
  • DateTime?
  • e qualsiasi altra struct

Wrapper Nullable per le struct più usate

Tipo normale Tipo Nullable Esempio
int
int?
int? a = null;
double
double?
double? x = 3.14;
bool
bool?
bool? ok = null;
DateTime
DateTime?
DateTime? d = null;

Puoi anche scrivere in modo più lungo, usando la classe wrapper:


Nullable<int> pages = null;
        
Forma lunga

Ma scrivere int? è più corto, quindi più figo.

3. Come usare un tipo nullable

Assegnazione e controllo

Assegnare null funziona come per i tipi reference:

Dichiarazione e assegnazione

int? temperature = null;
temperature = 25;

Controllo su null

Come capire se il nostro tipo nullable ha davvero un valore?

if (temperature != null)
{
    Console.WriteLine($"Temperatura: {temperature}");
}
else
{
    Console.WriteLine("Nessun dato sulla temperatura");
}

Proprietà dei tipi Nullable: .HasValue e .Value

I tipi nullable hanno due proprietà importanti:

  • .HasValue — restituisce true se la variabile contiene qualcosa (non null).
  • .Value — il valore vero e proprio, se c'è (altrimenti lancia un'eccezione).
int? temperature = null;
if (temperature.HasValue) //nessuna eccezione!
{
    Console.WriteLine($"Temperatura: {temperature.Value}°C");
}
else
{
    Console.WriteLine("Temperatura sconosciuta");
}

Questo codice funziona: temperature non è null, contiene null dentro. E puoi sempre chiamare la proprietà HasValue su un tipo Nullable. Ma provare a prendere .Value quando non c'è — brutta idea, ti becchi un'eccezione InvalidOperationException. Controlla sempre prima se c'è un valore!

Sintassi abbreviata per la stampa

Spesso basta usare la variabile nullable — e C# capisce tutto da solo:

int? hours = null;
Console.WriteLine(hours); // non stampa niente (solo vuoto)
hours = 10;
Console.WriteLine(hours); // stampa 10

4. Operazioni e tipi nullable: aritmetica, confronti, conversioni

Operazioni: cosa succede?

Se uno degli operandi è nullable, anche il risultato è nullable.
E se uno degli operandi è null, anche il risultato è null.

int? a = 5;
int? b = null;
int? sum = a + b; // sum == null

int? c = 10;
int? d = 15;
int? total = c + d; // total == 25

Confronti

Puoi confrontare tipi nullable con numeri normali:

int? score = null;
if (score > 0) Console.WriteLine("Ottimo risultato!");
else Console.WriteLine("Nessun risultato"); // Va qui

Se score è null, la condizione score > 0 sarà false.

Conversione esplicita e implicita

  • Da tipo normale a nullable: automatico.
  • Da nullable a normale: solo se non è null (altrimenti eccezione).
int? x = 3;
int y = x.Value; // Ok, se x non è null

// Implicito
int? z = y;

5. Nullable e metodi: parametri e valori di ritorno

Restituire valori nullable

Se un metodo non può sempre restituire un risultato, usa tipi nullable come valore di ritorno:

// Il metodo cerca un utente per login e restituisce la sua età se trovato, altrimenti null
int? FindUserAge(string login)
{
    // ... qui la logica di ricerca
    return null; // se non trovato
}

Parametri nullable

Puoi accettare valori nullable nei parametri, così è chiaro: “può esserci, ma anche no”.

void PrintTemperature(int? temp)
{
    if (temp == null)
        Console.WriteLine("Temperatura sconosciuta");
    else
        Console.WriteLine($"Temperatura: {temp} gradi");
}
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION