Partilhar via


Resolver avisos anuláveis

O objetivo dos avisos de nulidade é minimizar a chance de que o seu aplicativo lance um System.NullReferenceException durante a execução. Para atingir esse objetivo, o compilador usa análise estática e emite avisos quando seu código tem construções que podem levar a exceções de referência nula. Você fornece ao compilador informações para sua análise estática aplicando anotações de tipo e atributos. Essas anotações e atributos descrevem a anulabilidade de argumentos, parâmetros e membros de seus tipos. Neste artigo, você aprende diferentes técnicas para abordar os avisos anuláveis que o compilador gera a partir de sua análise estática. As técnicas descritas aqui são para código C# geral. Aprenda a trabalhar com tipos de referência anuláveis e o núcleo do Entity Framework em Trabalhando com tipos de referência anuláveis.

Tipos de referência anuláveis, incluindo os operadores ? e ! são permitidos somente quando o contexto anulável é definido como enable ou annotations. Você pode definir o contexto nulo usando a opção de compilador Nullable em seu arquivo de projeto ou usando o pragma #nullable em seu código-fonte.

Este artigo aborda os seguintes avisos do compilador:

  • CS8597 - Valor lançado pode ser nulo.
  • CS8598 - O operador de supressão não é permitido neste contexto
  • CS8600 - Convertendo literal nulo ou possível valor nulo para tipo não anulável.
  • CS8601 - Possível atribuição de referência nula.
  • CS8602 - Desreferência de uma referência possivelmente nula.
  • CS8603 - Possível retorno de referência nulo.
  • CS8604 - Possível argumento de referência nula para parâmetro.
  • CS8605 - Unboxing um valor possivelmente nulo.
  • CS8607 - Um possível valor nulo não pode ser usado para um tipo marcado com [NotNull] ou [DisallowNull]
  • CS8608 - A anulabilidade dos tipos de referência no tipo não corresponde ao membro substituído.
  • CS8609 - A anulabilidade dos tipos de referência no tipo de retorno não corresponde ao membro substituído.
  • CS8610 - A anulabilidade dos tipos de referência no parâmetro type não corresponde ao membro substituído.
  • CS8611 - A anulabilidade dos tipos de referência no parâmetro type não corresponde à declaração parcial do método.
  • CS8612 - A anulabilidade dos tipos de referência no tipo não corresponde ao membro implementado implicitamente.
  • CS8613 - A anulabilidade dos tipos de referência no tipo de retorno não corresponde ao membro implementado implicitamente.
  • CS8614 - A anulabilidade dos tipos de referência no tipo de parâmetro não corresponde ao membro implementado implicitamente.
  • CS8615 - A anulabilidade de tipos de referência no tipo não está em conformidade com o membro implementado.
  • CS8616 - A anulabilidade dos tipos de referência no tipo de retorno não corresponde ao membro implementado.
  • CS8617 - A anulabilidade dos tipos de referência no tipo de parâmetro não corresponde ao membro implementado.
  • CS8618 - A variável não anulável deve conter um valor não nulo ao sair do construtor. Considere declará-lo como anulável.
  • CS8619 - A anulabilidade dos tipos de referência no valor não corresponde ao tipo de destino.
  • O argumento CS8620 - não pode ser usado para parâmetro devido a diferenças na anulabilidade dos tipos de referência.
  • CS8621 - A nulabilidade dos tipos de referência no tipo de retorno não corresponde à do delegado de destino (possivelmente devido a atributos de nulabilidade).
  • CS8622 - A anulabilidade dos tipos de referência no tipo de parâmetro não corresponde ao delegado de destino (possivelmente devido a atributos de anulabilidade).
  • CS8623 - Não é permitida a aplicação explícita de System.Runtime.CompilerServices.NullableAttribute.
  • O argumento CS8624 - não pode ser usado como uma saída devido a diferenças na anulabilidade dos tipos de referência.
  • CS8625 - Não é possível converter literal nulo em tipo de referência não anulável.
  • CS8628 - Não é possível usar um tipo de referência anulável na criação de objetos.
  • CS8629 - Tipo de valor anulável pode ser nulo.
  • CS8631 - O tipo não pode ser utilizado como parâmetro de tipo no tipo genérico ou método. A anulabilidade do argumento de tipo não corresponde ao tipo de restrição.
  • CS8632 - A anotação para tipos de referência anuláveis só deve ser usada em código dentro de um contexto de anotações #nullable.
  • pt-PT: CS8633 - A nulabilidade nas restrições para o parâmetro de tipo do método não corresponde às restrições para o parâmetro de tipo do método da interface. Em vez disso, considere usar uma implementação explícita da interface.
  • CS8634 - O tipo não pode ser usado como parâmetro de tipo no tipo genérico ou método. A nulabilidade do argumento de tipo não corresponde à restrição 'class'.
  • CS8636 - Opção inválida para /nullable; deve ser disable, enable, warnings ou annotations
  • CS8637 - Esperado enable, disableou restore
  • CS8639 - O tipo de operador não pode ser usado em um tipo de referência anulável
  • CS8643 - A anulabilidade de tipos de referência no especificador de interface explícito não corresponde à interface implementada pelo tipo.
  • CS8644 - Type não implementa membro da interface. A anulabilidade dos tipos de referência na interface implementada pelo tipo base não corresponde.
  • CS8645 - Membro já está listado na lista de interfaces no tipo com diferente anulabilidade dos tipos de referência.
  • CS8655 - A expressão switch não manipula algumas entradas nulas (não é exaustiva).
  • CS8667 - As declarações de método parcial têm restrições de nulidade inconsistentes para o parâmetro de tipo.
  • CS8670 - Inicializador de objeto ou coleção desreferencia-se implicitamente a um membro possivelmente nulo.
  • CS8714 - O tipo não pode ser usado como parâmetro de tipo no tipo genérico ou método. A anulabilidade do argumento type não corresponde à restrição 'notnull'.
  • O parâmetro CS8762 - deve ter um valor não nulo ao sair.
  • CS8763 - Um método marcado [DoesNotReturn] não deve retornar.
  • CS8764 - A nulabilidade do tipo de retorno não corresponde ao membro substituído (possivelmente devido a atributos de nulabilidade).
  • CS8765 - A anulabilidade do tipo de parâmetro não corresponde ao membro substituído (possivelmente devido a atributos de anulabilidade).
  • CS8766 - A característica de nulabilidade dos tipos de referência no tipo de retorno não corresponde ao membro que é implementado implicitamente (possivelmente devido aos atributos relacionados à anulabilidade).
  • CS8767 - Anulabilidade de tipos de referência em tipo de parâmetro de não corresponde implicitamente membro implementado (possivelmente devido a atributos de anulabilidade).
  • CS8768 - A nulabilidade dos tipos de referência no tipo de retorno não corresponde ao membro implementado (possivelmente devido a atributos de nulabilidade).
  • CS8769 - A nulabilidade dos tipos de referência no tipo do parâmetro não corresponde ao membro implementado (possivelmente devido a atributos de nulabilidade).
  • CS8770 - Método carece de [DoesNotReturn] anotação para corresponder ao membro implementado ou substituído.
  • CS8774 - Membro deve ter um valor não nulo no momento de sair.
  • CS8776 - O membro não pode ser usado neste atributo.
  • CS8775 - Membro deve ter um valor não-nulo ao sair.
  • CS8777 - Parameter deve ter um valor não nulo ao sair.
  • CS8819 - A anulabilidade dos tipos de referência no tipo de retorno não corresponde à declaração parcial do método.
  • O parâmetro CS8824 - deve ter um valor não nulo ao sair porque o parâmetro não é nulo.
  • CS8825 - Valor de retorno deve ser não-nulo porque o parâmetro é não-nulo.
  • CS8847 - A expressão switch não manipula algumas entradas nulas (não é exaustiva). No entanto, um padrão com uma cláusula 'quando' pode corresponder com êxito a esse valor.

Observação

A análise estática nem sempre pode deduzir em que ordem, em um cenário específico, os métodos são acessados e se o método é concluído com êxito sem lançar uma exceção. Essas armadilhas conhecidas são bem descritas na seção Armadilhas conhecidas.

Você aborda quase todos os avisos usando uma das cinco técnicas:

  • Configurando o contexto anulável.
  • Adicionando verificações de nulidade necessárias.
  • Adicionar ou remover ? ou ! anotações anuláveis.
  • Adicionando atributos que descrevem semântica nula.
  • Inicializando variáveis corretamente.

Se você é novo no uso de tipos de referência anuláveis, a visão geral dos tipos de referência anuláveis fornece um plano de fundo sobre o que os tipos de referência anuláveis resolvem e como eles funcionam para fornecer avisos para possíveis erros em seu código. Você também pode verificar as instruções sobre como migrar para tipos de referência anuláveis para saber mais sobre como habilitar tipos de referência anuláveis em um projeto existente.

Configurar contexto anulável

Os avisos a seguir indicam que você não definiu o contexto anulável corretamente:

  • CS8632 - A anotação para tipos de referência anuláveis só deve ser usada em código dentro de um contexto de anotações #nullable.
  • CS8636 - opção inválida para /nullable; deve ser disable, enable, warnings ou annotations
  • CS8637 - enableesperado, disableou restore

Sintaxe de anotação incorreta

Esses erros e avisos indicam que o uso da anotação ! ou ? está incorreto.

  • CS8598 - O operador de supressão não é permitido neste contexto
  • CS8623 - Não é permitida a aplicação explícita de System.Runtime.CompilerServices.NullableAttribute.
  • CS8628 - Não é possível usar um tipo de referência anulável na criação de objetos.
  • CS8639 - O tipo de operador não pode ser usado em um tipo de referência anulável

A ? anotação em uma declaração indica que a variável pode ser nula. Ele não indica um tipo de tempo de execução diferente. Ambas as declarações a seguir são do mesmo tipo de tempo de execução:

string s1 = "a string";
string? s2 = "another string";

O ? é uma dica para o compilador sobre a expectativa de valores nulos.

A anotação ! em uma expressão indica que você sabe que a expressão é segura e deve ser assumida como não nula.

  • Você deve usar essas anotações, não o System.Runtime.CompilerServices.NullableAttribute em seu código.
  • Como o ? é uma anotação, não um tipo, não é possível usá-lo com expressões typeofou new.
  • O operador ! não pode ser aplicado a uma expressão variável ou a um grupo de métodos.
  • O operador ! não pode ser aplicado à esquerda de um operador de acesso membro, como obj.Field!.Method().

Possível desreferenciação de nulo

Esse conjunto de avisos alerta que você está desreferenciando uma variável cujo estado nulo é talvez-nulo. Estes avisos são:

  • CS8602 - Desreferência de uma referência possivelmente nula.
  • CS8670 - : Objeto ou inicializador de coleção implicitamente desreferencia possivelmente membro nulo.

O código a seguir demonstra um exemplo de cada um dos avisos anteriores:

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
}

No exemplo anterior, o aviso é porque o Container, c, pode ter um valor nulo para a propriedade States. A atribuição de novos estados a uma coleção que pode ser nula causa o aviso.

Para remover esses avisos, você precisa adicionar código para alterar o estado nulo dessa variável para não-nulo antes de desreferenciar ela. O aviso do inicializador da coleção pode ser mais difícil de detetar. O compilador deteta que a coleção pode ser nula quando o inicializador lhe adiciona elementos.

Em muitos casos, você pode corrigir esses avisos verificando se uma variável não é nula antes de desreferenciar ela. Considere o exemplo a seguir que adiciona uma verificação nula antes de desreferenciar o parâmetro message:

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

O exemplo a seguir inicializa o armazenamento de backup para o States e remove o set acessador. Os utilizadores da classe podem modificar o conteúdo da coleção, e o armazenamento da coleção nunca é:

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

Outros casos em que você recebe esses avisos podem ser falsos positivos. Você pode ter um método utilitário privado que verifica null. O compilador não sabe que o método fornece uma verificação nula. Considere o seguinte exemplo que usa um método de utilidade privada, IsNotNull:

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

O compilador avisa que você pode estar desreferenciando null quando você escreve a propriedade message.Length porque sua análise estática determina que message pode ser null. Você sabe que IsNotNull fornece uma verificação de nulidade e, quando retorna true, o estado nulo de de message deve ser não-nula. Você deve dizer ao compilador esses fatos. Uma maneira é usar o operador de perdão nulo, !. Você pode alterar a WriteLine instrução para corresponder ao seguinte código:

Console.WriteLine(message!.Length);

O operador de perdão nulo torna a expressão não-nula , mesmo que fosse talvez-nula sem o ! aplicado. Neste exemplo, uma solução melhor é adicionar um atributo à assinatura de IsNotNull:

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

O System.Diagnostics.CodeAnalysis.NotNullWhenAttribute informa ao compilador que o argumento usado para o obj parâmetro não é nulo quando o método retorna true. Quando o método retorna false, o argumento tem o mesmo estado nulo que tinha antes do método ser chamado.

Gorjeta

Há um rico conjunto de atributos que você pode usar para descrever como seus métodos e propriedades afetam o estado nulo. Você pode aprender sobre eles no artigo de referência de linguagem sobre Atributos de análise estática anuláveis.

A fixação de um aviso para desreferenciar uma variável talvez-nula envolve uma das três técnicas:

  • Adicione uma verificação nula ausente.
  • Adicione atributos de análise de nulos em APIs para afetar a análise estática de estado nulo do compilador. Esses atributos informam o compilador quando um valor de retorno ou argumento deve ser maybe-null ou not-null depois de chamar o método.
  • Aplique o operador de perdão nulo ! à expressão que força o estado a não-nulo.

Possível nulo atribuído a uma referência não anulável

Esse conjunto de avisos alerta que você está atribuindo uma variável cujo tipo não é anulável a uma expressão cujo estado nulo é talvez-nulo. Estes avisos são:

  • CS8597 - Valor lançado pode ser nulo.
  • CS8600 - Convertendo literal nulo ou possível valor nulo para tipo não anulável.
  • CS8601 - Possível atribuição de referência nula.
  • CS8603 - Possível retorno de referência nulo.
  • CS8604 - Possível argumento de referência nula para parâmetro.
  • CS8605 - Desembalar um valor possivelmente nulo.
  • CS8625 - Não é possível converter literal nulo em tipo de referência não anulável.
  • CS8629 - Tipo de valor anulável pode ser nulo.

O compilador emite esses avisos quando você tenta atribuir uma expressão que é talvez-nula a uma variável que não é anulável. Por exemplo:

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

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

Os diferentes avisos fornecem detalhes sobre o código, como atribuição, atribuição de unboxing, declarações de retorno, argumentos para métodos e expressões throw.

Você pode executar uma das três ações para lidar com esses avisos. Uma delas é adicionar a ? anotação para tornar a variável um tipo de referência anulável. Essa alteração pode causar outros avisos. Alterar uma variável de uma referência não anulável para uma referência anulável altera seu estado nulo padrão de não-nulo para talvez-nulo. A análise estática do compilador encontra instâncias em que você desreferencia uma variável que é talvez-nula .

As outras ações instruem o compilador que o lado direito da atribuição não é nulo. A expressão no lado direito pode ser verificada nula antes da atribuição, como mostrado no exemplo a seguir:

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

Os exemplos anteriores demonstram a atribuição do valor de retorno de um método. Você anota o método (ou propriedade) para indicar quando um método retorna um valor não-nulo. O System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute freqüentemente especifica que um valor de retorno não é nulo quando um argumento de entrada não é nulo. Outra alternativa é adicionar o operador de perdão nulo, ! no lado direito:

string msg = TryGetMessage(42)!;

A fixação de um aviso para atribuir uma expressão talvez-nula a uma variável não-nula envolve uma das quatro técnicas:

  • Altere o lado esquerdo da atribuição para um tipo anulável. Essa ação pode introduzir novos avisos quando você desreferenciar essa variável.
  • Forneça uma verificação nula antes da atribuição.
  • Anote a API que produz o lado direito da atribuição.
  • Adicione o operador que permite valores nulos ao lado direito da atribuição.

Referência não anulável não inicializada

Esse conjunto de avisos alerta que você está atribuindo uma variável cujo tipo não é anulável a uma expressão cujo estado nulo é talvez-nulo. Estes avisos são:

  • CS8618 - A variável não anulável deve conter um valor não nulo ao sair do construtor. Considere declará-lo como anulável.
  • O parâmetro CS8762 - deve ter um valor não nulo ao sair.

Considere a seguinte classe como exemplo:

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

Nem FirstName nem LastName são garantidos como inicializados. Se esse código for novo, considere alterar a interface pública. O exemplo anterior pode ser atualizado da seguinte forma:

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

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

Se você precisar criar um Person objeto antes de definir o nome, poderá inicializar as propriedades usando um valor padrão não nulo:

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

Outra alternativa é alterar esses membros para tipos de referência nulos. A Person classe pode ser definida da seguinte forma, se null deve ser permitida para o nome:

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

O código existente às vezes requer outras alterações para informar o compilador sobre a semântica nula para esses membros. Ele pode ter vários construtores e sua classe tem um método auxiliar particular que inicializa um ou mais membros. Você pode mover o código de inicialização para um único construtor e garantir que todos os construtores chamem aquele com o código de inicialização comum. Ou, você pode usar os System.Diagnostics.CodeAnalysis.MemberNotNullAttribute atributos e System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute . Esses atributos informam ao compilador que um membro é não nulo depois do retorno do método. O código a seguir mostra um exemplo de cada um. A Person classe usa um construtor comum chamado por todos os outros construtores. A Student classe tem um método auxiliar anotado com o System.Diagnostics.CodeAnalysis.MemberNotNullAttribute atributo:


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";
    }
}

Finalmente, você pode usar o operador de perdão nulo para indicar que um membro é inicializado em outro código. Para outro exemplo, considere as seguintes classes que representam um modelo 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!;
}

A DbSet propriedade é inicializada em null!. Isso informa ao compilador que a propriedade está definida como um valor não-nulo . Na verdade, a base DbContext executa a inicialização do conjunto. A análise estática do compilador não pega isso. Para obter mais informações sobre como trabalhar com tipos de referência anuláveis e Entity Framework Core, consulte o artigo sobre Trabalhando com tipos de referência anuláveis no EF Core.

A fixação de um aviso para não inicializar um membro não anulável envolve uma das quatro técnicas:

  • Altere os construtores ou inicializadores de campo para garantir que todos os membros não anuláveis sejam inicializados.
  • Altere um ou mais membros para serem tipos anuláveis.
  • Anote alguns métodos auxiliares para indicar a quais membros são atribuídos.
  • Adicione um inicializador a null! para indicar que o membro está inicializado noutro código.

Incompatibilidade na declaração de anulabilidade

Muitos avisos indicam incompatibilidades de anulabilidade entre assinaturas para métodos, delegados ou parâmetros de tipo.

  • CS8608 - A anulabilidade dos tipos de referência no tipo não corresponde ao membro substituído.
  • CS8609 - A anulabilidade dos tipos de referência no tipo de retorno não corresponde ao membro substituído.
  • CS8610 - A anulabilidade dos tipos de referência no parâmetro type não corresponde ao membro substituído.
  • CS8611 - A anulabilidade dos tipos de referência no parâmetro type não corresponde à declaração parcial do método.
  • CS8612 - A anulabilidade dos tipos de referência no tipo não corresponde ao membro implementado implicitamente.
  • CS8613 - A anulabilidade dos tipos de referência no tipo de retorno não corresponde ao membro implementado implicitamente.
  • CS8614 - A anulabilidade dos tipos de referência no tipo de parâmetro não corresponde ao membro implementado implicitamente.
  • CS8615 - A anulabilidade dos tipos de referência no tipo não corresponde ao membro implementado.
  • CS8616 - A anulabilidade dos tipos de referência no tipo de retorno não corresponde ao membro implementado.
  • CS8617 - A anulabilidade dos tipos de referência no tipo de parâmetro não corresponde ao membro implementado.
  • CS8619 - A anulabilidade dos tipos de referência no valor não corresponde ao tipo de destino.
  • O argumento CS8620 - não pode ser usado para parâmetro devido a diferenças na anulabilidade dos tipos de referência.
  • CS8621 - A anulabilidade dos tipos de referência no tipo de retorno não corresponde ao delegado de destino (possivelmente devido a atributos de anulabilidade).
  • CS8622 - A anulabilidade dos tipos de referência no tipo de parâmetro não corresponde ao delegado de destino (possivelmente devido a atributos de anulabilidade).
  • O argumento CS8624 - não pode ser usado como uma saída devido a diferenças na anulabilidade dos tipos de referência.
  • CS8631 - O tipo não pode ser usado como parâmetro de tipo no tipo genérico ou método. A anulabilidade do argumento type não corresponde ao tipo de restrição.
  • CS8633 - A nulabilidade nas restrições para o parâmetro de tipo do método não corresponde às restrições para o parâmetro de tipo do método da interface. Considere usar uma implementação explícita de interface.
  • CS8634 - O tipo não pode ser usado como parâmetro de tipo no tipo genérico ou método. A anulabilidade do argumento type não corresponde à restrição 'class'.
  • CS8643 - A anulabilidade de tipos de referência no especificador de interface explícito não corresponde à interface implementada pelo tipo.
  • CS8644 - O tipo não implementa o membro da interface. A nulidade dos tipos de referência na interface implementada pelo tipo base não corresponde.
  • CS8645 - Membro já está listado na lista de interface em tipo com diferentes anulabilidade de tipos de referência.
  • CS8667 - As declarações de método parcial têm anulabilidade inconsistente em restrições para o parâmetro de tipo.
  • CS8714 - O tipo não pode ser usado como parâmetro de tipo no tipo genérico ou método. A anulabilidade do argumento type não corresponde à restrição 'notnull'.
  • CS8764 - A anulabilidade do tipo de retorno não corresponde ao membro substituído (possivelmente devido a atributos de anulabilidade).
  • CS8765 - A anulabilidade do tipo de parâmetro não corresponde ao membro substituído (possivelmente devido a atributos de anulabilidade).
  • CS8766 - A anulabilidade dos tipos de referência no tipo de retorno não corresponde ao membro implementado implicitamente (possivelmente devido a atributos de anulabilidade).
  • CS8767 - A anulabilidade dos tipos de referência no tipo de parâmetro não corresponde ao membro implementado implicitamente (possivelmente devido a atributos de anulabilidade).
  • CS8768 - A anulabilidade dos tipos de referência no tipo de retorno não corresponde ao membro implementado (possivelmente devido a atributos de anulabilidade).
  • CS8769 - A anulabilidade dos tipos de referência no tipo de parâmetro não corresponde ao membro implementado (possivelmente devido a atributos de anulabilidade).
  • CS8819 - A anulabilidade dos tipos de referência no tipo de retorno não corresponde à declaração parcial do método.

O código a seguir demonstra CS8764:

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

O exemplo anterior mostra um método virtual numa classe base e um override com uma nullabilidade diferente. A classe base retorna uma cadeia de caracteres não anulável, mas a classe derivada retorna uma cadeia de caracteres anulável. Se os string e string? forem invertidos, isso seria permitido porque a classe derivada é mais restritiva. Da mesma forma, as declarações de parâmetros devem corresponder. Os parâmetros no método de substituição podem aceitar valores nulos mesmo quando a classe base não os permite.

Outras situações podem gerar esses avisos. Você tem uma incompatibilidade em uma declaração de método de interface e a implementação desse método. Ou um tipo de delegado e a expressão para esse delegado diferem. Um parâmetro type e o argumento type diferem em anulabilidade.

Para corrigir esses avisos, atualize a declaração apropriada.

O código não corresponde à declaração de atributo

As seções anteriores abordaram como pode utilizar Atributos para análise estática anulável para informar o compilador sobre a semântica de nulidade do seu código. O compilador avisa se o código não cumprir as garantias desse atributo.

  • CS8607 - Um possível valor nulo não pode ser usado para um tipo marcado com [NotNull] ou [DisallowNull]
  • CS8763 - Um método marcado [DoesNotReturn] não deve retornar.
  • O método CS8770 - não tem [DoesNotReturn] anotação para corresponder ao membro implementado ou substituído.
  • CS8774 - Membro deve ter um valor não-nulo ao sair.
  • CS8775 - Membro deve ter um valor não-nulo ao sair.
  • CS8776 - Member não pode ser usado neste atributo.
  • CS8777 - Parameter deve ter um valor não nulo ao sair.
  • O parâmetro CS8824 - deve ter um valor não nulo ao sair porque o parâmetro não é nulo.
  • CS8825 - Valor de retorno deve ser não-nulo porque o parâmetro é não-nulo.

Considere o seguinte método:

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

}

O compilador produz um aviso porque o message parâmetro é atribuído nulle o método retorna true. O NotNullWhen atributo indica que isso não deveria acontecer.

Para lidar com esses avisos, atualize seu código para que ele corresponda às expectativas dos atributos aplicados. Você pode alterar os atributos ou o algoritmo.

Expressão exaustiva do interruptor

As expressões do switch devem ser exaustivas, o que significa que todos os valores de entrada devem ser manipulados. Mesmo para tipos de referência não anuláveis, o null valor deve ser contabilizado. O compilador emite avisos quando o valor nulo não é manipulado:

  • CS8655 - A expressão switch não manipula algumas entradas nulas (não é exaustiva).
  • CS8847 - A expressão switch não manipula algumas entradas nulas (não é exaustiva). No entanto, um padrão com uma cláusula 'quando' pode corresponder com êxito a esse valor.

O código de exemplo a seguir demonstra essa condição:

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

A expressão de entrada é um string, não um string?. O compilador ainda gera esse aviso. O { } padrão manipula todos os valores não nulos, mas não corresponde ao null. Para resolver esses erros, você pode adicionar um caso explícito null ou substituir o { } pelo _ padrão (descartar). O padrão de descarte corresponde a "nulo", além de qualquer outro valor.