Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A finalidade dos avisos anuláveis é minimizar a chance do aplicativo gerar System.NullReferenceException quando executado. Para atingir essa meta, o compilador usa a análise estática e emite avisos quando seu código tem constructos que podem levar a exceções de referência nulas. Você fornece ao compilador informações para análise estática aplicando anotações de tipo e atributos. Essas anotações e atributos descrevem a nulidade de argumentos, parâmetros e membros de seus tipos. Neste artigo, você aprenderá diferentes técnicas para abordar os avisos anuláveis gerados pelo compilador a partir de sua análise estática. As técnicas descritas aqui são para o código C# geral. Saiba como trabalhar com tipos de referência anuláveis e o Entity Framework Core em Trabalhar 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 anulável usando a Nullable
opção do compilador no arquivo de projeto ou usar o pragma #nullable
no código-fonte.
Este artigo aborda os seguintes avisos do compilador:
- CS8597 - Valor gerado pode ser nulo.
- CS8598 - O operador de supressão não é permitido neste contexto
- CS8600 - Convertendo literal nulo ou possível valor nulo em 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 nula.
- CS8604 - Possível argumento de referência nula para parâmetro.
- CS8605 - Conversão unboxing de um valor possivelmente nulo.
- CS8607 - Um possível valor nulo pode não ser usado para um tipo marcado com
[NotNull]
ou[DisallowNull]
- CS8608 - A nulidade de tipos de referência no tipo não corresponde ao membro substituído.
- CS8609 - A nulidade de tipos de referência no tipo de retorno não corresponde ao membro substituído.
- CS8610 - A nulidade de tipos de referência no parâmetro de tipo não corresponde ao membro substituído.
- CS8611 - A nulidade de tipos de referência em tipo de parâmetro não corresponde à declaração de método parcial.
- CS8612 - A nulidade de tipos de referência no tipo não corresponde ao membro implementado implicitamente.
- CS8613 - A nulidade de tipos de referência no tipo de retorno não corresponde ao membro implementado implicitamente.
- CS8614 - A nulidade de tipos de referência no tipo de parâmetro não corresponde ao membro implementado implicitamente.
- CS8615 - A nulidade de tipos de referência no tipo não corresponde ao membro implementado.
- CS8616 - A nulidade de tipos de referência no tipo de retorno não corresponde ao membro implementado.
- CS8617 - A nulidade de tipos de referência no tipo de parâmetro não corresponde ao membro implementado.
- CS8618 - 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 nulidade de tipos de referência no valor não corresponde ao tipo de destino.
- CS8620 - O argumento não pode ser usado para o parâmetro devido a diferenças na nulidade dos tipos de referência.
- CS8621 - A nulidade de tipos de referência no tipo de retorno não corresponde ao delegado de destino (possivelmente devido a atributos de nulidade).
- CS8622 - A nulidade de tipos de referência no tipo de parâmetro não corresponde ao delegado de destino (possivelmente devido a atributos de nulidade).
- CS8623 - A aplicação
System.Runtime.CompilerServices.NullableAttribute
explícita não é permitida. - CS8624 - O argumento não pode ser usado como uma saída devido a diferenças na nulidade 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 objeto.
- CS8629 - Tipo de valor anulável pode ser nulo.
- CS8631 - O tipo não pode ser usado como parâmetro de tipo no tipo genérico ou método. A nulidade 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 no código dentro de um
#nullable
contexto de anotações. - CS8633 - A nulidade em 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 de interface. Em vez disso, considere usar uma implementação de interface explícita.
- CS8634 - O tipo não pode ser usado como parâmetro de tipo no tipo genérico ou método. A nulidade do argumento de tipo não corresponde à restrição 'class'.
- CS8636 - Opção inválida para
/nullable
; deve serdisable
,enable
warnings
ouannotations
- CS8637 - Esperado
enable
,disable
, ourestore
- CS8639 - O operador typeof não pode ser usado em um tipo de referência anulável
- CS8643 - A nulidade dos 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 de tipos de referência na interface implementada pelo tipo base não corresponde.
- CS8645 - O membro já está listado na lista de interfaces no tipo com nulidade diferente de tipos de referência.
- CS8655 - A expressão switch não manipula algumas entradas nulas (ela não é finita).
- CS8667 - Declarações de método parcial têm nulidade inconsistente em restrições para o parâmetro de tipo.
- CS8670 - Objeto ou inicializador de coleção desreferencia implicitamente possivelmente membro nulo.
- CS8714 - O tipo não pode ser usado como parâmetro de tipo no tipo genérico ou método. A nulidade do argumento de tipo não corresponde à restrição 'notnull'.
- CS8762 - O parâmetro deve ter um valor não nulo ao sair.
- CS8763 - O método marcado como
[DoesNotReturn]
não deve retornar. - CS8764 - A nulidade do tipo de retorno não corresponde ao membro substituído (possivelmente devido a atributos de nulidade).
- CS8765 - A nulidade do tipo de parâmetro não corresponde ao membro substituído (possivelmente devido a atributos de nulidade).
- CS8766 - A nulidade de tipos de referência no tipo de retorno não corresponde ao membro implementado implicitamente (possivelmente devido a atributos de nulidade).
- CS8767 - A nulidade de tipos de referência no tipo de parâmetro não corresponde ao membro implementado implicitamente (possivelmente devido a atributos de nulidade).
- CS8768 - A nulidade de tipos de referência no tipo de retorno não corresponde ao membro implementado (possivelmente devido a atributos de nulidade).
- CS8769 - A nulidade de tipos de referência no tipo de parâmetro não corresponde ao membro implementado (possivelmente devido a atributos de nulidade).
- CS8770 - O método não tem a anotação
[DoesNotReturn]
para corresponder ao membro implementado ou substituído. - CS8774 - O membro deve ter um valor não nulo ao sair.
- CS8776 - O membro não pode ser usado nesse atributo.
- CS8775 - O membro deve ter um valor não nulo ao sair.
- CS8777 - O parâmetro deve ter um valor não nulo ao sair.
- CS8819 - A nulidade de tipos de referência no tipo de retorno não corresponde à declaração de método parcial.
- CS8824 - O parâmetro deve ter um valor não nulo ao sair porque o parâmetro não é nulo.
- CS8825 - O valor retornado precisa 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 'when' pode corresponder com êxito a esse valor.
Observação
A análise estática nem sempre pode deduzir em qual ordem, em um cenário específico, os métodos são acessados e se o método é concluído com êxito sem gerar 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 nulas necessárias.
- Adicionando ou removendo anotações
?
ou!
anuláveis. - Adicionando atributos que descrevem a semântica nula.
- Inicializando variáveis corretamente.
Se você não estiver familiarizado com o uso de tipos de referência anuláveis, a visão geral dos tipos de referência anuláveis fornece uma tela de fundo sobre quais tipos de referência anuláveis resolvem e como eles funcionam para fornecer avisos a possíveis erros em seu código. Você também pode verificar as diretrizes 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 o 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 que permitem valor nulo só deve ser usada no código dentro de um
#nullable
contexto de anotações. - CS8636 - Opção inválida para
/nullable
; deve serdisable
,enable
warnings
ouannotations
- CS8637 - Esperado
enable
,disable
ourestore
Para definir o contexto anulável corretamente, você tem duas opções:
Configuração no nível do projeto: adicione o
<Nullable>
elemento ao arquivo de projeto:<PropertyGroup> <Nullable>enable</Nullable> </PropertyGroup>
Configuração em nível de arquivo: use diretivas de pré-processador no código-fonte:
#nullable enable
O contexto nulo possui dois sinalizadores independentes que controlam diferentes aspectos:
- Sinalizador de anotação: controla se você pode usar
?
para declarar tipos de referência anuláveis e!
para suprimir avisos individuais. - Sinalizador de aviso: controla se o compilador emite avisos de nulidade
Para obter informações detalhadas sobre contextos anuláveis e estratégias de migração, consulte:
- Visão geral dos tipos de referência anuláveis
- Atualizar uma base de código com tipos de referência anuláveis
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 - A aplicação
System.Runtime.CompilerServices.NullableAttribute
explícita não é permitida. - CS8628 - Não é possível usar um tipo de referência anulável na criação de objeto.
- CS8639 - O operador typeof 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 runtime diferente. Ambas as declarações a seguir são do mesmo tipo de runtime:
string s1 = "a string";
string? s2 = "another string";
A ?
é 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 considerada não nula.
- Você deve usar essas anotações, não o System.Runtime.CompilerServices.NullableAttribute no seu código.
- Como
?
é uma anotação, não um tipo, você não pode usá-la comtypeof
ounew
expressões. - 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 do lado esquerdo de um operador de acesso de membro, comoobj.Field!.Method()
.
Possível desreferência do 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 desreferencia implicitamente possivelmente membro nulo.
O seguinte código 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 States
propriedade. Atribuir novos estados a uma coleção que pode ser nula causa o aviso.
Para remover esses avisos, é necessário adicionar código para alterar o estado nulo dessa variável para não nulo antes de desreferenciá-la. O aviso do inicializador de coleção pode ser mais difícil de detectar. O compilador detecta que a coleção talvez seja nula quando o inicializador adiciona elementos a ela.
Em muitas instâncias, você pode corrigir esses avisos verificando se uma variável não é nula antes de desreferenciá-la. Considere o exemplo a seguir que adiciona uma verificação nula antes de desreferenciar o message
parâmetro:
void WriteMessageLength(string? message)
{
if (message is not null)
{
Console.WriteLine(message.Length);
}
}
O exemplo a seguir inicializa o armazenamento com suporte para States
e remove o acessador set
. Os consumidores da classe podem modificar o conteúdo da coleção, e o armazenamento da coleção nunca é null
:
class Container
{
public List<string> States { get; } = new();
}
Outras situações quando você recebe esses avisos podem ser falsos positivos. Você pode ter um método utilitário privado que testa se é nulo. O compilador não sabe que o método fornece uma verificação nula. Considere o exemplo a seguir que usa um método utilitário privado IsNotNull
:
public void WriteMessage(string? message)
{
if (IsNotNull(message))
Console.WriteLine(message.Length);
}
O compilador avisa que você pode estar desreferenciando um valor nulo ao atribuir 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 message
deve ser não nulo. Você deve informar esses fatos ao compilador. Uma maneira é usar o operador tolerante a nulo !
. Você pode alterar a instrução WriteLine
para corresponder ao seguinte código:
Console.WriteLine(message!.Length);
O operador tolerante a nulo torna a expressão não nula ainda que ela fosse talvez nula sem o !
aplicado. Neste exemplo, uma solução melhor é a inclusão de um atributo à assinatura de IsNotNull
:
private static bool IsNotNull([NotNullWhen(true)] object? obj) => obj != null;
System.Diagnostics.CodeAnalysis.NotNullWhenAttribute informa ao compilador que o argumento usado para o parâmetro obj
é 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.
Dica
Há um conjunto avançado de atributos que podem ser usados para descrever como seus métodos e propriedades afetam o estado nulo. Você pode aprender sobre eles no artigo de referência de idioma em Análise estática que permite valor nulo.
A correção de um aviso para desreferenciar uma variável talvez nula envolve uma das três técnicas:
- Adicionar uma verificação nula ausente.
- Adicione atributos de análise nulos em APIs para afetar a análise estática do estado nulo do compilador. Esses atributos informam o compilador quando um valor ou argumento retornado deve ser talvez nulo ou não nulo depois de chamar o método.
- Aplique o operador
!
de perdão nulo à expressão que força o estado a não ser 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 pode ser nulo a uma expressão cujo estado nulo é talvez nulo. Estes avisos são:
- CS8597 - Valor gerado pode ser nulo.
- CS8600 - Convertendo literal nulo ou possível valor nulo em tipo não anulável.
- CS8601 - Possível atribuição de referência nula.
- CS8603 - Possível retorno de referência nula.
- CS8604 - Possível argumento de referência nula para parâmetro.
- CS8605 - Conversão unboxing de um valor possivelmente nulo.
- CS8625 - Não é possível converter literal nulo em tipo de referência não anulável.
- CS8629 - O tipo de valor anulável pode ser nulo.
O compilador emite esses avisos quando você tenta atribuir uma expressão talvez nula a uma variável não anulável. Por exemplo:
string? TryGetMessage(int id) => "";
string msg = TryGetMessage(42); // Possible null assignment.
Os avisos diferentes fornecem detalhes sobre o código, como atribuição, atribuição de unboxing, instruções de retorno, argumentos para métodos e gerar expressões.
Você pode executar uma das três ações para resolver 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 o estado nulo padrão de não nulo para talvez nulo. A análise estática do compilador localiza instâncias em que você desreferencia uma variável que talvez seja nula.
As outras ações informam ao compilador que o lado direito da atribuição é não nulo. A expressão no lado direito pode ser marcada como nula antes da atribuição, conforme mostrado no exemplo a seguir:
string notNullMsg = TryGetMessage(42) ?? "Unknown message id: 42";
Os exemplos anteriores demonstram a atribuição ao valor retornado de um método. Você anota o método (ou propriedade) para indicar quando um método retorna um valor não nulo. Geralmente System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute especifica que um valor retornado é não nulo quando um argumento de entrada é não nulo. Uma alternativa é adicionar o operador tolerante a nulo!
ao lado direito:
string msg = TryGetMessage(42)!;
A correção de um aviso para atribuir uma expressão talvez nula a uma variável não nula envolve uma das quatro técnicas:
- Alterar o lado esquerdo da atribuição para um tipo anulável. Essa ação pode introduzir novos avisos quando você desreferenciar essa variável.
- Fornecer uma verificação nula antes da atribuição.
- Anotar a API que produz o lado direito da atribuição.
- Adicionar o operador tolerante a nulo 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 pode ser nulo a uma expressão cujo estado nulo é talvez nulo. Estes avisos são:
- CS8618 - Variável não anulável deve conter um valor não nulo ao sair do construtor. Considere declará-lo como anulável.
- CS8762 - O parâmetro deve ter um valor não nulo ao sair.
Considere a seguinte classe a título de exemplo:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
FirstName
ou LastName
não são garantidos inicializados. Se o código for novo, considere alterar a interface pública. O exemplo anterior pode ser atualizado da seguinte maneira:
public class Person
{
public Person(string first, string last)
{
FirstName = first;
LastName = last;
}
public string FirstName { get; set; }
public string LastName { get; set; }
}
Caso seja necessário criar um objeto Person
antes de definir o nome, será possível inicializar as propriedades usando um valor não nulo padrão:
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 que permitem valor nulo. A classe Person
poderá ser definida da seguinte maneira se null
for permitido para o nome:
public class Person
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
}
O código existente às vezes exige 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 privado 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 atributos System.Diagnostics.CodeAnalysis.MemberNotNullAttribute e System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute. Esses atributos informam ao compilador que um membro não é nulo após o retorno do método. O código a seguir mostra um exemplo de cada um desses casos. A classe Person
usa um construtor comum chamado por todos os outros construtores. A classe Student
tem um método auxiliar anotado com o atributo 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";
}
}
Por fim, você pode usar o operador tolerante a nulo para indicar que um membro é inicializado em outro código. Para obter 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 propriedade DbSet
é inicializada com null!
. Isso informa ao compilador que a propriedade foi 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 capta isso. Para obter mais informações sobre como trabalhar com tipos de referência anuláveis e o Entity Framework Core, consulte o artigo sobre Como trabalhar com Tipos de Referência Anuláveis no EF Core.
A correção de um aviso para não inicializar um membro não anulável envolve uma das quatro técnicas:
- Alterar os construtores ou inicializadores de campo para garantir que todos os membros não anuláveis sejam inicializados.
- Alterar um ou mais membros para serem tipos anuláveis.
- Anotar quaisquer métodos auxiliares para indicar quais membros são atribuídos.
- Adicione um inicializador para
null!
indicar que o membro é inicializado em outro código.
Incompatibilidade na declaração de nulidade
Muitos avisos indicam incompatibilidades de nulidade entre assinaturas de métodos, delegados ou parâmetros de tipo.
- CS8608 - A nulidade de tipos de referência no tipo não corresponde ao membro substituído.
- CS8609 - A nulidade de tipos de referência no tipo de retorno não corresponde ao membro substituído.
- CS8610 - A nulidade de tipos de referência no parâmetro de tipo não corresponde ao membro substituído.
- CS8611 - A nulidade de tipos de referência em tipo de parâmetro não corresponde à declaração de método parcial.
- CS8612 - A nulidade de tipos de referência no tipo não corresponde ao membro implementado implicitamente.
- CS8613 - A nulidade de tipos de referência no tipo de retorno não corresponde ao membro implementado implicitamente.
- CS8614 - A nulidade de tipos de referência no tipo de parâmetro não corresponde ao membro implementado implicitamente.
- CS8615 - A nulidade de tipos de referência no tipo não corresponde ao membro implementado.
- CS8616 - A nulidade de tipos de referência no tipo de retorno não corresponde ao membro implementado.
- CS8617 - A nulidade de tipos de referência no tipo de parâmetro não corresponde ao membro implementado.
- CS8619 - A nulidade de tipos de referência no valor não corresponde ao tipo de destino.
- CS8620 - O argumento não pode ser usado para o parâmetro devido a diferenças na nulidade dos tipos de referência.
- CS8621 - A nulidade de tipos de referência no tipo de retorno não corresponde ao delegado de destino (possivelmente devido a atributos de nulidade).
- CS8622 - A nulidade de tipos de referência no tipo de parâmetro não corresponde ao delegado de destino (possivelmente devido a atributos de nulidade).
- CS8624 - O argumento não pode ser usado como uma saída devido a diferenças na nulidade 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 nulidade do argumento de tipo não corresponde ao tipo de restrição.
- CS8633 - A nulidade em 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 de interface. Em vez disso, considere usar uma implementação de interface explícita.
- CS8634 - O tipo não pode ser usado como parâmetro de tipo no tipo genérico ou método. A nulidade do argumento de tipo não corresponde à restrição 'class'.
- CS8643 - A nulidade dos 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 de tipos de referência na interface implementada pelo tipo base não corresponde.
- CS8645 - O membro já está listado na lista de interfaces no tipo com nulidade diferente de tipos de referência.
- CS8667 - Declarações de método parcial têm nulidade 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 nulidade do argumento de tipo não corresponde à restrição 'notnull'.
- CS8764 - A nulidade do tipo de retorno não corresponde ao membro substituído (possivelmente devido a atributos de nulidade).
- CS8765 - A nulidade do tipo de parâmetro não corresponde ao membro substituído (possivelmente devido a atributos de nulidade).
- CS8766 - A nulidade de tipos de referência no tipo de retorno não corresponde ao membro implementado implicitamente (possivelmente devido a atributos de nulidade).
- CS8767 - A nulidade de tipos de referência no tipo de parâmetro não corresponde ao membro implementado implicitamente (possivelmente devido a atributos de nulidade).
- CS8768 - A nulidade de tipos de referência no tipo de retorno não corresponde ao membro implementado (possivelmente devido a atributos de nulidade).
- CS8769 - A nulidade de tipos de referência no tipo de parâmetro não corresponde ao membro implementado (possivelmente devido a atributos de nulidade).
- CS8819 - A nulidade de tipos de referência no tipo de retorno não corresponde à declaração de método parcial.
O seguinte código demonstra o erro 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
em uma classe base e um override
com nulidade 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 string
e string?
forem invertidos, ele será permitido porque a classe derivada é mais restritiva. Da mesma forma, as declarações de parâmetro devem corresponder. Os parâmetros no método de substituição podem permitir o nulo mesmo quando a classe base não permite.
Outras situações podem gerar esses avisos. Você tem uma incompatibilidade em uma declaração de método de interface e na implementação desse método. Ou um tipo de delegado e a expressão desse delegado diferem. Um parâmetro de tipo e o argumento de tipo diferem na nulidade.
Para corrigir esses avisos, atualize a declaração apropriada.
O código não corresponde à declaração de atributo
As seções anteriores discutiram como você pode usar Atributos para análise estática anulável para informar o compilador sobre a semântica nula do código. O compilador avisará se o código não cumprir as promessas desse atributo:
- CS8607 - Um possível valor nulo pode não ser usado para um tipo marcado com
[NotNull]
ou[DisallowNull]
- CS8763 - Um método marcado como
[DoesNotReturn]
não deve retornar. - CS8770 - O método não tem a anotação
[DoesNotReturn]
para corresponder ao membro implementado ou substituído. - CS8774 - O membro deve ter um valor não nulo ao sair.
- CS8775 - O membro deve ter um valor não nulo ao sair.
- CS8776 - O membro não pode ser usado nesse atributo.
- CS8777 - O parâmetro deve ter um valor não nulo ao sair.
- CS8824 - O parâmetro deve ter um valor não nulo ao sair porque o parâmetro não é nulo.
- CS8825 - O valor retornado precisa ser não nulo porque o parâmetro não é nulo.
Considere o método a seguir:
public bool TryGetMessage(int id, [NotNullWhen(true)] out string? message)
{
message = null;
return true;
}
O compilador produz um aviso porque o parâmetro message
é atribuído null
e o método retorna true
. O atributo NotNullWhen
indica que isso não deve acontecer.
Para resolver esses avisos, atualize o código para que ele corresponda às expectativas dos atributos aplicados. Você pode alterar os atributos ou o algoritmo.
Expressões de switch exaustivas
As expressões de comutador devem ser exaustivas, o que significa que todos os valores de entrada devem ser tratados. Mesmo para tipos de referência não anuláveis, o valor null
deve ser contabilizado. O compilador emite avisos quando o valor nulo não é tratado:
- CS8655 - A expressão switch não manipula algumas entradas nulas (ela não é finita).
- CS8847 - A expressão switch não manipula algumas entradas nulas (não é exaustiva). No entanto, um padrão com uma cláusula 'when' 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 a null
. Para resolver esses erros, você pode adicionar um caso de null
explícito ou substituir o { }
pelo padrão _
(descarte). O padrão de descarte corresponde a nulo, além de qualquer outro valor.