Tipi valore nullable: Nozioni fondamentali su C#

Suggerimento

Questo articolo fa parte della sezione Nozioni fondamentali per gli sviluppatori che conoscono almeno un linguaggio di programmazione e stanno imparando C#. Se non si ha familiarità con la programmazione, iniziare prima con le esercitazioni introduttive . Per altri dettagli, vedere Tipi di valore nullable nella guida di riferimento del linguaggio.

Un tipo di valore nullableT? rappresenta tutti i valori del tipo di valore T sottostante, oltre a un valore aggiuntivo null. Una variabile di tipo int? contiene qualsiasi integer o null per rappresentare "nessun valore".

I tipi di valore, come int, bool e DateTime, non possono contenere null per impostazione predefinita. Questo comportamento è efficiente e impedisce molti errori. Tuttavia, questa limitazione crea un problema quando un valore potrebbe effettivamente essere assente. Uno scenario comune è la lettura da un database: una colonna integer potrebbe contenere un numero oppure potrebbe non contenere alcun valore (NULL in SQL). Un semplice int non può rappresentare quell'assenza, ma int? può.

Dichiarare un tipo di valore annullabile

Aggiungere ? a qualsiasi tipo di valore per renderlo nullable:

int?    age      = null;    // integer with no value yet
double? price    = 9.99;    // nullable double with a value
bool?   isActive = null;    // boolean with no value

age = 30;                   // assign a value later

int?[] scores = [100, null, 85, null, 72]; // array with absent entries

Il valore predefinito di un tipo valore nullable è null, non l'impostazione predefinita del tipo sottostante.

Controllare se è presente un valore

Il modo consigliato per controllare un tipo di valore nullable ed estrarne il valore è con un criterio di tipo:

int? temperature = 72;

if (temperature is int degrees)
{
    Console.WriteLine($"Temperature is {degrees}°F.");
}
else
{
    Console.WriteLine("Temperature is not recorded.");
}
// Output: Temperature is 72°F.

Lo schema is int degrees corrisponde solo quando temperature è diverso da null e associa simultaneamente il valore a degrees. Il controllo Null e l'estrazione dei valori vengono visualizzati in un unico passaggio.

In alternativa, usare le HasValue proprietà e Value :

int? count = 42;

if (count.HasValue)
{
    Console.WriteLine($"Count is {count.Value}.");
}
else
{
    Console.WriteLine("Count has no value.");
}
// Output: Count is 42.

Preferisci il pattern is T value per il nuovo codice. Introduce una nuova variabile non annullabile con ambito al ramo corrispondente, che rende più chiara la finalità ed elimina qualsiasi tentazione di usare Value accidentalmente all'esterno di un controllo di null, dove genererebbe un'eccezione InvalidOperationException.

È anche possibile confrontare direttamente con null:

int? quantity = null;

if (quantity != null)
{
    Console.WriteLine($"Quantity: {quantity.Value}");
}
else
{
    Console.WriteLine("Quantity is not set.");
}
// Output: Quantity is not set.

Ottenere un valore con un fallback

Quando è necessario ottenere un valore non annullabile da un valore annullabile, usare GetValueOrDefault o l'operatore null-coalescing ?? :

int? rating = null;

int result1 = rating.GetValueOrDefault();    // 0 (default for int)
int result2 = rating.GetValueOrDefault(-1);  // -1 (specified fallback)

Console.WriteLine(result1); // 0
Console.WriteLine(result2); // -1

rating = 5;
int result3 = rating.GetValueOrDefault(-1);  // 5 (actual value)
Console.WriteLine(result3); // 5

L'operatore ?? è spesso più pulito in linea.

int? priority = null;

int effective = priority ?? 0;  // 0 because priority is null
Console.WriteLine(effective);   // 0

priority  = 3;
effective = priority ?? 0;      // 3 because priority has a value
Console.WriteLine(effective);   // 3

Entrambi gli approcci restituiscono il valore effettivo quando è presente e il valore di riserva specificato quando non lo è.

Aritmetica con tipi di valore nullable

Gli operatori aritmetici e di confronto su tipi di valore nullable vengono elevati: quando uno degli operandi è , il risultato è null anziché un errore.

int? a = 10;
int? b = 20;
int? c = null;

int? sum     = a + b;   // both non-null: result is 30
int? product = a * c;   // one operand is null: result is null

Console.WriteLine(sum);               // 30
Console.WriteLine(product.HasValue);  // False — null propagates through arithmetic

Null viene propagato nell'aritmetica per impostazione predefinita. Per evitare che un risultato Null venga ulteriormente propagato, estrarre il valore con ?? o GetValueOrDefault prima di usarlo in un calcolo.

Vedi anche