Risolvere gli avvisi nullable

Questo articolo illustra gli avvisi del compilatore seguenti:

  • CS8597 - Il valore generato può essere Null.
  • CS8600 - Conversione di valori letterali Null o possibile Null in un tipo che non ammette i valori Null.
  • CS8601 - Possibile assegnazione di riferimento Null.
  • CS8602 - Dereferenziamento di un riferimento eventualmente Null.
  • CS8603 - Possibile riferimento Null restituito.
  • CS8604 - Argomento di riferimento Null possibile per il parametro.
  • CS8605 - Conversione unboxing di un valore eventualmente null.
  • CS8607 - Un possibile valore Null non può essere usato per un tipo contrassegnato con [NotNull] o [DisallowNull]
  • CS8608 - Il spporto dei valori Null dei tipi riferimento nel tipo non corrisponde al membro sottoposto a override.
  • CS8609 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde al membro sottoposto a override.
  • CS8610 - Il supporto dei valori Null dei tipi riferimento nel parametro di tipo non corrisponde al membro sottoposto a override.
  • CS8611 - Il supporto dei valori Null dei tipi riferimento nel parametro di tipo non corrisponde alla dichiarazione di metodo parziale.
  • CS8612 - Il supporto dei valori Null dei tipi riferimento nel tipo non corrisponde al membro implementato in modo implicito.
  • CS8613 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde al membro implementato in modo implicito.
  • CS8614 - Il supporto dei valori Null dei tipi riferimento nel tipo di parametro non corrisponde al membro implementato in modo implicito.
  • CS8615 - Il supporto dei valori Null dei tipi riferimento nel tipo non corrisponde al membro implementato.
  • CS8616 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde al membro implementato.
  • CS8617 - Il supporto dei valori Null dei tipi riferimento nel tipo di parametro non corrisponde al membro implementato.
  • CS8618 - La variabile che non ammette i valori Null deve contenere un valore non Null quando si esce dal costruttore. Valutare la possibilità di dichiararla una variabile che ammette i valori Null.
  • CS8619 - Il supporto dei valori Null dei tipi riferimento in valore non corrisponde al tipo di destinazione.
  • CS8620 - L'argomento non può essere usato per il parametro a causa di differenze nel supporto dei valori Null dei tipi di riferimento.
  • CS8621 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde al delegato di destinazione (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8622 - Il supporto dei valori Null dei tipi riferimento nel tipo di parametro non corrisponde al delegato di destinazione (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8624 - L'argomento non può essere usato come output a causa di differenze nel supporto dei valori Null dei tipi di riferimento.
  • CS8625 - Non è possibile convertire un valore letterale Null in un tipo riferimento che non ammette i valori Null.
  • CS8629 - Il tipo di valore che ammette i valori Null può essere Null.
  • CS8631 - Il tipo non può essere usato come parametro di tipo nel tipo o nel metodo generico. Il supporto dei valori Null dell'argomento di tipo non corrisponde al tipo di vincolo.
  • CS8633 - Il supporto dei valori Null ù nei vincoli per il parametro di tipo del metodo non corrisponde ai vincoli per il parametro di tipo del metodo di interfaccia. Provare a usare un'implementazione esplicita dell'interfaccia.
  • CS8634 - Il tipo non può essere utilizzato come parametro di tipo nel tipo o nel metodo generico. Il supporto dei valori Null dell'argomento di tipo non corrisponde al vincolo 'class'.
  • CS8643 - Il supporto dei valori Null dei tipi riferimento nell'identificatore di interfaccia esplicito non corrisponde all'interfaccia implementata dal tipo.
  • CS8644 - Il tipo non implementa il membro dell'interfaccia. Il supporto dei valori Null dei tipi riferimento nell'interfaccia implementata dal tipo di base non corrisponde.
  • CS8645 - Il membro è già elencato nell'elenco di interfacce di tipo con valori Null diversi dei tipi di riferimento.
  • CS8655 - L'espressione switch non gestisce alcuni input Null (non è esaustivo).
  • CS8667 - Le dichiarazioni di metodi parziali hanno un supporto dei valori Null incoerente nei vincoli per il parametro di tipo.
  • CS8670 - L’inizializzatore di elemento o di oggetto deferenzia in modo implicito un membro eventualmente Null.
  • CS8714 - Il tipo non può essere usato come parametro di tipo nel tipo o nel metodo generico. Il supporto dei valori Null dell'argomento di tipo non corrisponde al vincolo 'notnull'.
  • CS8762 - Il parametro deve avere un valore non Null quando si esce.
  • CS8763 - Un metodo contrassegnato [DoesNotReturn] non deve restituire.
  • CS8764 - Il supporto dei valori Null del tipo restituito non corrisponde al membro sottoposto a override (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8765 - Il supporto dei valori Null di tipo di parametro non corrisponde al membro sottoposto a override (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8766 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito di non corrisponde al membro implementato in modo implicito (possibilmente a causa di attributi del supporto dei valori Null).
  • CS8767 - Il supporto dei valori Null dei tipi riferimento nel tipo di parametro di non corrisponde al membro implementato in modo implicito (probabilmente a causa di attributi di supporto dei valori Null).
  • CS8768 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde al membro implementato (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8769 - Il supporto dei valori Null dei tipi riferimento nel tipo di parametro non corrisponde al membro implementato (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8770 - Il metodo non dispone dell'annotazione [DoesNotReturn]per trovare la corrispondenza con il membro implementato o sottoposto a override.
  • CS8774 - Il membro deve avere un valore non Null quando si esce.
  • CS8776 - Il membro non può essere utilizzato in questo attributo.
  • CS8775 - Il membro deve avere un valore diverso da Null quando si esce.
  • CS8777 - Il parametro deve avere un valore non Null quando si esce.
  • CS8819 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde alla dichiarazione di metodo parziale.
  • CS8824 - Il parametro deve avere un valore non Null quando si esce perché il parametro è diverso da null.
  • CS8825 - Il valore restituito deve essere non Null perché il parametro è non Null.
  • CS8847 - L'espressione switch non gestisce alcuni input Null (non è esaustivo). Tuttavia, un criterio con una clausola 'when' potrebbe corrispondere correttamente a questo valore.

Lo scopo degli avvisi che ammettono i valori Null è ridurre al minimo la probabilità che l'applicazione generi un'eccezione durante l'esecuzione di System.NullReferenceException. Per raggiungere questo obiettivo, il compilatore usa l'analisi statica e genera avvisi quando il codice include costrutti che possono causare eccezioni di riferimento Null. È possibile fornire al compilatore informazioni per l'analisi statica applicando annotazioni e attributi di tipo. Queste annotazioni e attributi descrivono i valori Null di argomenti, parametri e membri dei tipi. In questo articolo verranno illustrate diverse tecniche per risolvere gli avvisi che ammettono i valori Null generati dal compilatore dall'analisi statica. Le tecniche descritte di seguito sono per il codice C# generale. Informazioni su come usare i tipi riferimento nullable e Entity Framework Core in Uso di tipi riferimento nullable.

Verranno affrontati quasi tutti gli avvisi usando una delle quattro tecniche seguenti:

  • Aggiunta di controlli Null necessari.
  • Aggiunta di annotazioni che ammettono i valori Null ? o !.
  • Aggiunta di attributi che descrivono la semantica Null.
  • Inizializzazione corretta delle variabili.

Possibile dereferenziazione di null

Questo set di avvisi avvisa che si sta dereferenziando una variabile il cui stato null è forse null. Questi avvisi sono:

  • CS8602 - Dereferenziamento di un riferimento possibilmente Null.
  • CS8670 - L’inizializzatore di elemento o di oggetto deferenzia in modo implicito un membro eventualmente Null.

Il codice seguente illustra un esempio di ognuno degli avvisi precedenti:

class Container
{
    public List<string>? States { get; set; }
}

internal void PossibleDereferenceNullExamples(string? message)
{
    Console.WriteLine(message.Length); // CS8602

    var c = new Container { States = { "Red", "Yellow", "Green" } }; // CS8670
}

Nell'esempio precedente, l'avviso è dovuto al fatto che Container, c, può avere un valore Null per la proprietà States. L'assegnazione di nuovi stati a una raccolta che potrebbe essere Null causa l'avviso.

Per rimuovere questi avvisi, è necessario aggiungere codice per modificare lo stato null della variabile in non Null prima di dereferenziarlo. L'avviso dell'inizializzatore di elemento può essere più difficile da individuare. Il compilatore rileva che la raccolta potrebbe essere Null quando l'inizializzatore vi aggiunge elementi.

In molti casi, è possibile correggere questi avvisi controllando che una variabile non sia Null prima di dereferenziarla. Considerare quanto segue che aggiunge un controllo Null prima di dereferenziare il parametro message:

void WriteMessageLength(string? message)
{
    if (message is not null)
    {
        Console.WriteLine(message.Length);
    }
    
}

Nell'esempio seguente viene inizializzata l'archiviazione di backup per States e viene rimossa la funzione di accesso set. I consumer della classe possono modificare il contenuto della raccolta e l'archiviazione per la raccolta non è mai null:

class Container
{
    public List<string> States { get; } = new();
}

Altre istanze quando vengono visualizzati questi avvisi possono essere falsi positivi. È possibile che si disponga di un metodo di utilità privata che esegue il test per i valori Null. Il compilatore non sa che il metodo fornisce un controllo Null. Si consideri l'esempio seguente che usa un metodo di utilità privata, IsNotNull:

public void WriteMessage(string? message)
{
    if (IsNotNull(message))
        Console.WriteLine(message.Length);
}

Il compilatore avvisa che è possibile dereferenziare null quando si scrive la proprietà message.Length perché l'analisi statica determina che message può essere null. È possibile sapere che IsNotNull fornisce un controllo Null e quando restituisce true, lo stato Null di message deve essere non Null. È necessario indicare al compilatore tali fatti. Un modo consiste nell'usare l'operatore forgiving Null, !. È possibile modificare l'istruzione WriteLine in modo che corrisponda al codice seguente:

Console.WriteLine(message!.Length);

L'operatore di forgiving Null rende l'espressione non Null, anche se era forse Null senza l'oggetto ! applicato. In questo esempio, una soluzione migliore consiste nell'aggiungere un attributo alla firma di IsNotNull:

private static bool IsNotNull([NotNullWhen(true)] object? obj) => obj != null;

System.Diagnostics.CodeAnalysis.NotNullWhenAttribute informa il compilatore che l'argomento utilizzato per il parametro obj è non Null quando il metodo restituisce true. Quando il metodo restituisce false, l'argomento ha lo stesso stato Null che aveva prima della chiamata al metodo.

Suggerimento

È disponibile un set completo di attributi che è possibile usare per descrivere il modo in cui i metodi e le proprietà influiscono sullo stato Null. Per informazioni su di essi, vedere l'articolo di riferimento sul linguaggio sugli attributi di analisi statica che ammettono i valori Null.

La correzione di un avviso per la dereferenziazione di una variabile forse Null prevede una delle tre tecniche seguenti:

  • Aggiungere un controllo Null mancante.
  • Aggiungere attributi di analisi Null nelle API per influire sull'analisi statica dello stato Null del compilatore. Questi attributi informano il compilatore quando un valore restituito o un argomento deve essere forse null o non null dopo aver chiamato il metodo.
  • Applicare l'operatore ! di forgiving Null all'espressione per forzare lo stato su non Null.

Possibile valore Null assegnato a un riferimento non nullable

Questo set di avvisi avvisa che si sta assegnando una variabile il cui tipo non è nullable a un'espressione il cui stato null è forse Null. Questi avvisi sono:

  • CS8597 - Il valore generato può essere Null.
  • CS8600 - Conversione di valori letterali Null o possibile Null in un tipo che non ammette i valori Null.
  • CS8601 - Possibile assegnazione di riferimento Null.
  • CS8603 - Possibile riferimento Null restituito.
  • CS8604 - Argomento di riferimento Null possibile per il parametro.
  • CS8605 - Conversione unboxing di un valore eventualmente null.
  • CS8625 - Non è possibile convertire un valore letterale Null in un tipo riferimento che non ammette i valori Null.
  • CS8629 - Il tipo di valore che ammette i valori Null può essere Null.

Il compilatore genera questi avvisi quando si tenta di assegnare un'espressione che è forse null a una variabile che non è nullable. Ad esempio:

string? TryGetMessage(int id) => "";

string msg = TryGetMessage(42);  // Possible null assignment.

I diversi avvisi indicano informazioni dettagliate sul codice, ad esempio assegnazione, assegnazione di conversione unboxing, istruzioni restituite, argomenti ai metodi e espressioni throw.

È possibile eseguire una delle tre azioni per risolvere questi avvisi. Uno consiste nell'aggiungere l'annotazione ? per rendere la variabile un tipo riferimento nullable. Tale modifica può causare altri avvisi. La modifica di una variabile da un riferimento che non ammette i valori Null a un riferimento che ammette i valori Null modifica il relativo stato Null predefinito da non Null a forse Null. L'analisi statica del compilatore può trovare istanze in cui si dereferenzia una variabile che è forse null.

Le altre azioni indicano al compilatore che il lato destro dell'assegnazione è non Null. L'espressione sul lato destro potrebbe essere controllata da Null prima dell'assegnazione, come illustrato nell'esempio seguente:

string notNullMsg = TryGetMessage(42) ?? "Unknown message id: 42";

Negli esempi precedenti viene illustrata l'assegnazione del valore restituito di un metodo. È possibile annotare il metodo (o la proprietà) per indicare quando un metodo restituisce un valore non Null. Spesso System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute specifica che un valore restituito è non Null quando un argomento di input è non Null. Un'altra alternativa consiste nell'aggiungere l'operatore di forgiving Null, ! sul lato destro:

string msg = TryGetMessage(42)!;

La correzione di un avviso per l'assegnazione di un'espressione forse Null a una variabile non Null prevede una delle quattro tecniche seguenti:

  • Modificare il lato sinistro dell'assegnazione in un tipo nullable. Questa azione può introdurre nuovi avvisi quando si dereferenzia tale variabile.
  • Specificare un controllo null prima dell'assegnazione.
  • Annotare l'API che produce il lato destro dell'assegnazione.
  • Aggiungere l'operatore di forgiving Null sul lato destro dell'assegnazione.

Riferimento non nullable non inizializzato

Questo set di avvisi avvisa che si sta assegnando una variabile il cui tipo è non nullable a un'espressione il cui stato null è forse-null. Questi avvisi sono:

  • CS8618 - La variabile non nullable deve contenere un valore non Null quando si esce dal costruttore. Valutare la possibilità di dichiararla come nullable.
  • CS8762 - Il parametro deve avere un valore non Null quando si esce.

Si consideri la classe seguente come esempio:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

FirstNameLastName sono garantiti inizializzati. Se questo codice è nuovo, è consigliabile modificare l'interfaccia pubblica. L'esempio precedente può essere aggiornato come segue:

public class Person
{
    public Person(string first, string last)
    {
        FirstName = first;
        LastName = last;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Se è necessario creare un oggetto Person prima di impostare il nome, è possibile inizializzare le proprietà usando un valore non Null predefinito:

public class Person
{
    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
}

Un'altra alternativa può essere quella di modificare tali membri in tipi riferimento nullable. La classe Person può essere definita come segue se null deve essere consentita per il nome:

public class Person
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
}

Il codice esistente può richiedere altre modifiche per informare il compilatore sulla semantica Null per tali membri. È possibile che siano stati creati più costruttori e che la classe abbia un metodo helper privato che inizializza uno o più membri. È possibile spostare il codice di inizializzazione in un singolo costruttore e assicurarsi che tutti i costruttori chiamino quello con il codice di inizializzazione comune. In alternativa, è possibile usare gli attributi System.Diagnostics.CodeAnalysis.MemberNotNullAttribute e System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute. Questi attributi informano il compilatore che un membro è non Null dopo la chiamata del metodo. Il codice seguente visualizza un esempio con ogni metodo. La classe Person usa un costruttore comune chiamato da tutti gli altri costruttori. La classe Student ha un metodo helper annotato con l'attributo System.Diagnostics.CodeAnalysis.MemberNotNullAttribute:


using System.Diagnostics.CodeAnalysis;

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public Person() : this("John", "Doe") { }
}

public class Student : Person
{
    public string Major { get; set; }

    public Student(string firstName, string lastName, string major)
        : base(firstName, lastName)
    {
        SetMajor(major);
    }

    public Student(string firstName, string lastName) :
        base(firstName, lastName)
    {
        SetMajor();
    }

    public Student()
    {
        SetMajor();
    }

    [MemberNotNull(nameof(Major))]
    private void SetMajor(string? major = default)
    {
        Major = major ?? "Undeclared";
    }
}

Infine, è possibile usare l'operatore di forgiving Null per indicare che un membro viene inizializzato in altro codice. Per un altro esempio, considerare le classi seguenti che rappresentano un modello Entity Framework Core:

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

public class TodoContext : DbContext
{
    public TodoContext(DbContextOptions<TodoContext> options)
        : base(options)
    {
    }

    public DbSet<TodoItem> TodoItems { get; set; } = null!;
}

La proprietà DbSet viene inizializzata su null!. Indica al compilatore che la proprietà è impostata su un valore da non Null. Infatti, la base DbContext esegue l'inizializzazione del set. L'analisi statica del compilatore non rileva tale analisi. Per altre informazioni sull'uso dei tipi riferimento nullable e di Entity Framework Core, vedere l'articolo Uso di tipi di riferimento nullable in EF Core.

La correzione di un avviso per non inizializzare un membro non nullable prevede una delle quattro tecniche seguenti:

  • Modificare i costruttori o gli inizializzatori di campo per assicurarsi che tutti i membri non nullable vengano inizializzati.
  • Modificare uno o più membri in modo che siano tipi nullable.
  • Annotare qualsiasi metodo helper per indicare quali membri vengono assegnati.
  • Aggiungere un inizializzatore a null! per indicare che il membro viene inizializzato in altro codice.

Dichiarazione di mancata corrispondenza di valori Null

Molti avvisi indicano la mancata corrispondenza dei valori Null tra le firme per metodi, delegati o parametri di tipo.

  • CS8608 - Il supporto dei valori Null dei tipi riferimento nel tipo non corrisponde al membro sottoposto a override.
  • CS8609 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde al membro sottoposto a override.
  • CS8610 - Il supporto dei valori Null dei tipi riferimento nel parametro di tipo non corrisponde al membro sottoposto a override.
  • CS8611 - Il supporto dei valori Null dei tipi riferimento nel parametro di tipo non corrisponde alla dichiarazione di metodo parziale.
  • CS8612 - Il supporto dei valori Null dei tipi riferimento nel tipo non corrisponde al membro implementato in modo implicito.
  • CS8613 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde al membro implementato in modo implicito.
  • CS8614 - Il supporto dei valori Null dei tipi riferimento nel tipo di parametro non corrisponde al membro implementato in modo implicito.
  • CS8615 - Il supporto dei valori Null dei tipi riferimento nel tipo non corrisponde al membro implementato.
  • CS8616 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde al membro implementato.
  • CS8617 - Il supporto dei valori Null dei tipi riferimento nel tipo di parametro non corrisponde al membro implementato.
  • CS8619 - Il supporto dei valori Null dei tipi riferimento nel valore non corrisponde al tipo di destinazione.
  • CS8620 - L'argomento non può essere usato per il parametro a causa di differenze nel supporto dei valori Null dei tipi di riferimento.
  • CS8621 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde al delegato di destinazione (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8622 - Il supporto dei valori Null dei tipi riferimento nel tipo di parametro non corrisponde al delegato di destinazione (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8624 - L'argomento non può essere usato come output a causa di differenze nel supporto dei valori Null dei tipi di riferimento.
  • CS8631 - Il tipo non può essere usato come parametro di tipo nel tipo o nel metodo generico. Il supporto dei valori Null dell'argomento di tipo non corrisponde al tipo di vincolo.
  • CS8633 - Il supporto dei valori Null ù nei vincoli per il parametro di tipo del metodo non corrisponde ai vincoli per il parametro di tipo del metodo di interfaccia. Provare a usare un'implementazione esplicita dell'interfaccia.
  • CS8634 - Il tipo non può essere utilizzato come parametro di tipo nel tipo o nel metodo generico. Il supporto dei valori Null dell'argomento di tipo non corrisponde al vincolo 'class'.
  • CS8643 - Il supporto dei valori Null dei tipi riferimento nell'identificatore di interfaccia esplicito non corrisponde all'interfaccia implementata dal tipo.
  • CS8644 - Il tipo non implementa il membro dell'interfaccia. Il supporto dei valori Null dei tipi riferimento nell'interfaccia implementata dal tipo di base non corrisponde.
  • CS8645 - Il membro è già elencato nell'elenco di interfacce di tipo con valori Null diversi dei tipi di riferimento.
  • CS8667 - Le dichiarazioni di metodi parziali hanno un supporto dei valori Null incoerente nei vincoli per il parametro di tipo.
  • CS8714 - Il tipo non può essere usato come parametro di tipo nel tipo o nel metodo generico. I valori Null dell'argomento di tipo non corrispondono al vincolo 'non Null'.
  • CS8764 - Il supporto dei valori Null del tipo restituito non corrisponde al membro sottoposto a override (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8765 - Il supporto dei valori Null di tipo di parametro non corrisponde al membro sottoposto a override (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8766 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito di non corrisponde al membro implementato in modo implicito (possibilmente a causa di attributi del supporto dei valori Null).
  • CS8767 - Il supporto dei valori Null dei tipi riferimento nel tipo di parametro di non corrisponde al membro implementato in modo implicito (probabilmente a causa di attributi di supporto dei valori Null).
  • CS8768 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde al membro implementato (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8769 - Il supporto dei valori Null dei tipi riferimento nel tipo di parametro non corrisponde al membro implementato (probabilmente a causa di attributi del supporto dei valori Null).
  • CS8819 - Il supporto dei valori Null dei tipi riferimento nel tipo restituito non corrisponde alla dichiarazione di metodo parziale.

Il codice seguente illustra CS8764:

public class B
{
    public virtual string GetMessage(string id) => string.Empty;
}
public class D : B
{
    public override string? GetMessage(string? id) => default;
}

L'esempio precedente mostra un metodo virtual in una classe di base e un oggetto override con supporto dei valori Null diverso. La classe base restituisce una stringa che non ammette i valori Null, ma la classe derivata restituisce una stringa che ammette i valori Null. Se string e string? sono invertiti, sarebbe consentito perché la classe derivata è più restrittiva. Analogamente, le dichiarazioni dei parametri devono corrispondere. I parametri nel metodo di override possono consentire null anche quando la classe base non lo fa.

Altre situazioni possono generare questi avvisi. Potrebbe verificarsi una mancata corrispondenza in una dichiarazione di metodo di interfaccia e l'implementazione di tale metodo. Oppure un tipo delegato e l'espressione per tale delegato possono differire. Un parametro di tipo e l'argomento di tipo possono differire in termini di supporto dei valori Null.

Per correggere questi avvisi, aggiornare la dichiarazione appropriata.

Il codice non corrisponde alla dichiarazione dell'attributo

Le sezioni precedenti hanno illustrato come usare Attributi per l'analisi statica nullable per informare il compilatore sulla semantica Null del codice. Il compilatore avvisa se il codice non rispetta le promesse di tale attributo:

  • CS8607 - Un possibile valore Null non può essere usato per un tipo contrassegnato con [NotNull] o [DisallowNull]
  • CS8763 - Un metodo contrassegnato [DoesNotReturn] non deve restituire.
  • CS8770 - Il metodo non dispone dell'annotazione [DoesNotReturn] per trovare la corrispondenza con il membro implementato o sottoposto a override.
  • Il membro CS8774 - deve avere un valore non Null quando si esce.
  • CS8775 - Il membro deve avere un valore non Null quando si esce.
  • CS8776 - Il membro non può essere utilizzato in questo attributo.
  • CS8777 - Il parametro deve avere un valore non Null quando si esce.
  • CS8824 - Il parametro deve avere un valore non Null quando si esce perché il parametro è non null.
  • CS8825 - Il valore restituito deve essere non null perché il parametro è non null.

Si consideri il modello seguente:

public bool TryGetMessage(int id, [NotNullWhen(true)] out string? message)
{
    message = null;
    return true;

}

Il compilatore genera un avviso perché il parametro message è assegnato nulle il metodo restituisce true. L'attributo NotNullWhen indica che non deve verificarsi.

Per risolvere questi avvisi, aggiornare il codice in modo che corrisponda alle aspettative degli attributi applicati. È possibile modificare gli attributi o l'algoritmo.

Espressione switch esaustiva

Le espressioni switch devono essere esaustive, ovvero tutti i valori di input devono essere gestiti. Anche per i tipi riferimento che non ammettono i valori Null, il valore null deve essere tenuto in considerazione. Il compilatore genera avvisi quando il valore Null non viene gestito:

  • CS8655 - L'espressione switch non gestisce alcuni input Null (non è esaustivo).
  • CS8847 - L'espressione switch non gestisce alcuni input Null (non è esaustivo). Tuttavia, un criterio con una clausola 'when' potrebbe corrispondere correttamente a questo valore.

Il codice di esempio seguente illustra questa condizione:

int AsScale(string status) =>
    status switch
    {
        "Red" => 0,
        "Yellow" => 5,
        "Green" => 10,
        { } => -1
    };

L'espressione di input è un oggetto string, non un oggetto string?. Il compilatore genera comunque questo avviso. Il criterio { } gestisce tutti i valori non Null, ma non corrisponde a null. Per risolvere questi errori, è possibile aggiungere un caso null esplicito o sostituire { } con il modello (discard) _. Il criterio di eliminazione corrisponde a Null e a qualsiasi altro valore.