0Pricing
C# Academy · Lezione

Annotazioni: ?, !, MaybeNull e NotNull

Usi ? per i tipi nullable, ! per ignorare gli avvisi di nullabilità e attributi come MaybeNull e NotNullWhen per un'analisi precisa del flusso.

Annotazioni: ?, !, MaybeNull e NotNull è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.

Oltre ? e !: attributi di nullabilità

L'annotazione di base ? e il controllo null gestiscono la maggior parte dei casi, ma alcuni pattern richiedono annotazioni più espressive. Lo spazio dei nomi System.Diagnostics.CodeAnalysis fornisce attributi che offrono al compilatore informazioni più approfondite sul flusso dei valori null.

MaybeNull e NotNull

[MaybeNull] comunica al compilatore che un tipo restituito non nullable potrebbe in realtà essere null (ad esempio, in un metodo generico). [NotNull] garantisce che un parametro nullable non sarà null dopo la chiamata.

using System.Diagnostics.CodeAnalysis;

// [MaybeNull]: return might be null even though T is non-nullable
[return: MaybeNull]
public T Find<T>(int id)
{
    // Returns default(T) which is null for reference types
    return _cache.TryGetValue(id, out var val) ? val : default!;
}

// [NotNull]: after this call, output is guaranteed non-null
public static void EnsureNotNull<T>(
    [NotNull] ref T? value,
    T defaultValue) where T : class
{
    value ??= defaultValue;
}

NotNullWhen: non null condizionale

[NotNullWhen(true)] comunica al compilatore che un parametro di output non è null quando il metodo restituisce true. È così che viene annotato il pattern standard TryParse.

using System.Diagnostics.CodeAnalysis;

public static bool TryParseEmail(
    string? input,
    [NotNullWhen(true)] out string? email)
{
    if (input?.Contains('@') == true)
    {
        email = input.Trim().ToLower();
        return true;
    }
    email = null;
    return false;
}

// Usage — no warning after true check:
if (TryParseEmail(raw, out var email))
    Console.WriteLine(email.Length); // safe — email is non-null here

MaybeNullWhen: null condizionale

[MaybeNullWhen(false)] è l'inverso: l'output potrebbe essere null quando il metodo restituisce false. Viene utilizzato nei pattern TryGetValue dei dizionari.

// This is how Dictionary<K,V>.TryGetValue is annotated:
public bool TryGetValue(
    TKey key,
    [MaybeNullWhen(false)] out TValue value)
{ ... }

// Usage:
if (!dict.TryGetValue("key", out var value))
    return; // early return — value is null in this branch

Console.WriteLine(value.Length); // safe after the guard

AllowNull e DisallowNull

[AllowNull] su una proprietà non nullable consente ai chiamanti di passarle null (ad esempio, a un setter che converte null in una stringa vuota). [DisallowNull] vieta null su un tipo nullable.

public class Config
{
    private string _name = "";

    // Allow setting null (setter converts null -> empty)
    [AllowNull]
    public string Name
    {
        get => _name;
        set => _name = value ?? "";
    }

    // Getter always returns non-null: fine
    // Setter accepts null: [AllowNull] tells compiler that's OK
}

NotNullIfNotNull: propagazione della nullabilità

[NotNullIfNotNull(paramName)] indica che, se il parametro X non è null, anche il valore restituito non è null. È utile per le funzioni di trasformazione.

[return: NotNullIfNotNull(nameof(value))]
public static string? Normalize(string? value)
{
    return value?.Trim().ToLower();
}

// Usage:
string  name = "  Alice  ";
string  norm1 = Normalize(name)!; // guaranteed non-null
string? raw   = GetRaw();
string? norm2 = Normalize(raw);   // still nullable (raw might be null)

DoesNotReturn

[DoesNotReturn] contrassegna un metodo che genera sempre un'eccezione. Il compilatore sa che il codice successivo alla chiamata è irraggiungibile e sopprime gli avvisi di null superflui.

using System.Diagnostics.CodeAnalysis;

[DoesNotReturn]
public static void ThrowNotFound(int id)
    => throw new KeyNotFoundException($"Entity {id} not found");

// Usage — no null warning after the call:
var order = _db.Orders.Find(id);
if (order is null) ThrowNotFound(id);

Console.WriteLine(order.Id); // no CS8602 — compiler knows ThrowNotFound threw

MemberNotNull: post-condizione sui campi

[MemberNotNull] comunica al compilatore che un metodo garantisce che determinati campi non siano null dopo la sua restituzione. È utile per gli helper di inizializzazione lazy.

public class DataLoader
{
    private string? _data;

    [MemberNotNull(nameof(_data))]
    private void EnsureLoaded()
    {
        if (_data is null)
            _data = LoadFromFile();
    }

    public string GetData()
    {
        EnsureLoaded();
        return _data; // no CS8603 — compiler knows _data is set
    }
}

Combinazione delle annotazioni

Gli attributi possono essere combinati per definire contratti API precisi. Ecco un helper fluent di guardia che combina diversi attributi.

public static class Guard
{
    [return: NotNull]
    public static T NotNull<T>(
        [NotNull][AllowNull] T? value,
        [CallerArgumentExpression(nameof(value))] string? name = null)
        where T : class
    {
        ArgumentNullException.ThrowIfNull(value, name);
        return value;
    }
}

// Usage:
var product = Guard.NotNull(await _repo.FindAsync(id));
Console.WriteLine(product.Name); // no warning

Operatori null: ?. ?? ??=

Gli operatori condizionale null (?.), di coalescenza null (??) e di assegnazione con coalescenza null (??=) consentono di scrivere codice conciso e sicuro rispetto ai valori null, senza controlli if prolissi.

string? name = GetName();

// ?. safe navigation
int? len = name?.Length;
string? upper = name?.ToUpper().Trim();

// ?? default value
string display = name ?? "Anonymous";

// ??= lazy init
name ??= "Default";

// Chaining
string result = user?.Profile?.DisplayName ?? user?.Name ?? "Guest";

Verifica rapida

Che cosa comunica al compilatore [NotNullWhen(true)] applicato a un parametro out?

Riepilogo: annotazioni di nullabilità

Punti chiave:

  • [NotNullWhen(true)]: pattern TryParse: non null quando restituisce true
  • [MaybeNull]: un tipo non nullable può comunque restituire null (valori predefiniti generici)
  • [DoesNotReturn]: il metodo genera sempre un'eccezione; il codice successivo è irraggiungibile
  • [MemberNotNull]: il metodo garantisce che i campi siano impostati dopo la restituzione
  • ?., ??, ??=: navigazione sicura rispetto ai valori null e valori predefiniti in forma concisa

Domande Frequenti

La lezione «Annotazioni: ?, !, MaybeNull e NotNull» è gratuita?

Sì — il testo completo di «Annotazioni: ?, !, MaybeNull e NotNull» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.

Cosa imparerò in «Annotazioni: ?, !, MaybeNull e NotNull»?

Usi ? per i tipi nullable, ! per ignorare gli avvisi di nullabilità e attributi come MaybeNull e NotNullWhen per un'analisi precisa del flusso. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare C# Academy?

Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Annotazioni: ?, !, MaybeNull e NotNull»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione C# Academy?

Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Abilitazione e comprensione di NRT
  2. Annotazioni: ?, !, MaybeNull e NotNull
  3. Operatori null-conditional e null-coalescing
  4. Migrazione di una codebase a NRT
← Torna a C# Academy