Partilhar via


Atualizar uma base de código com tipos de referência anuláveis para melhorar os avisos de diagnóstico nulos

Os tipos de referência anuláveis permitem declarar se as variáveis de um tipo de referência devem ou não receber um null valor. A análise estática do compilador e os avisos quando seu código pode desreferenciar null são o benefício mais importante desse recurso. Uma vez ativado, o compilador gera avisos que ajudam a evitar lançar um System.NullReferenceException quando o código é executado.

Se sua base de código for relativamente pequena, você poderá ativar o recurso em seu projeto, endereçar avisos e aproveitar os benefícios do diagnóstico aprimorado. Bases de código maiores podem exigir uma abordagem mais estruturada para lidar com avisos ao longo do tempo, habilitando o recurso para alguns à medida que você aborda avisos em diferentes tipos ou arquivos. Este artigo descreve diferentes estratégias para atualizar uma base de código e as compensações associadas a essas estratégias. Antes de iniciar a migração, leia a visão geral conceitual dos tipos de referência anuláveis. Ele abrange a análise estática do compilador, valores de estado nulo de maybe-null e not-null e as anotações anuláveis. Quando estiver familiarizado com esses conceitos e termos, você estará pronto para migrar seu código.

Planear a migração

Independentemente de como você atualiza sua base de código, o objetivo é que avisos anuláveis e anotações anuláveis sejam habilitados em seu projeto. Depois de atingir esse objetivo, você terá a <nullable>Enable</nullable> configuração em seu projeto. Você não precisará de nenhuma das diretivas do pré-processador para ajustar as configurações em outro lugar.

A primeira opção é definir o padrão para o projeto. As suas opções são:

  1. Nullable disable como padrão: disable é o padrão se você não adicionar um Nullable elemento ao seu arquivo de projeto. Use esse padrão quando não estiver adicionando ativamente novos arquivos à base de código. A atividade principal é atualizar a biblioteca para usar tipos de referência anuláveis. Usar esse padrão significa que você adiciona uma diretiva de pré-processador anulável a cada arquivo à medida que atualiza seu código.
  2. Nullable enable as the default: defina esse padrão quando estiver desenvolvendo ativamente novos recursos. Você deseja que todo o novo código se beneficie de tipos de referência anuláveis e análise estática anulável. Usar esse padrão significa que você deve adicionar um #nullable disable à parte superior de cada arquivo. Você removerá essas diretivas de pré-processador à medida que aborda os avisos em cada arquivo.
  3. Avisos anuláveis como padrão: escolha este padrão para uma migração de duas fases. Na primeira fase, aborde os avisos. Na segunda fase, ative as anotações para declarar o estado nulo esperado de uma variável. Usar esse padrão significa que você deve adicionar um #nullable disable à parte superior de cada arquivo.
  4. Anotações anuláveis como padrão. Anote o código antes de endereçar avisos.

Habilitar nullable como padrão cria mais trabalho inicial para adicionar as diretivas de pré-processador a cada arquivo. A vantagem é que cada novo arquivo de código adicionado ao projeto será anulável habilitado. Qualquer novo trabalho será anulável; apenas o código existente deve ser atualizado. A desativação de nullable como padrão funciona melhor se a biblioteca for estável, e o foco principal do desenvolvimento é adotar tipos de referência anuláveis. Você ativa tipos de referência anuláveis à medida que anota APIs. Quando terminar, você habilitará tipos de referência anuláveis para todo o projeto. Ao criar um novo arquivo, você deve adicionar as diretivas de pré-processador e torná-lo anulável. Se algum desenvolvedor da sua equipe esquecer, esse novo código está agora na lista de pendências de trabalho para tornar todo o código anulável.

Qual dessas estratégias você escolhe depende de quanto desenvolvimento ativo está ocorrendo em seu projeto. Quanto mais maduro e estável for o seu projeto, melhor será a segunda estratégia. Quanto mais recursos forem desenvolvidos, melhor será a primeira estratégia.

Importante

O contexto global anulável não se aplica aos arquivos de código gerados. Em qualquer uma das estratégias, o contexto anulável é desabilitado para qualquer arquivo de origem marcado como gerado. Isso significa que todas as APIs nos arquivos gerados não são anotadas. Há quatro maneiras pelas quais um arquivo é marcado como gerado:

  1. No .editorconfig, especifique generated_code = true em uma seção que se aplica a esse arquivo.
  2. Coloque <auto-generated> ou <auto-generated/> em um comentário na parte superior do arquivo. Ele pode estar em qualquer linha nesse comentário, mas o bloco de comentários deve ser o primeiro elemento no arquivo.
  3. Inicie o nome do arquivo com TemporaryGeneratedFile_
  4. Termine o nome do arquivo com .designer.cs, .generated.cs, .g.cs ou .g.i.cs.

Os geradores podem optar por participar usando a diretiva de #nullable pré-processador.

Compreender contextos e avisos

A habilitação de avisos e anotações controla como o compilador visualiza os tipos de referência e a anulabilidade. Cada tipo tem uma de três nullabilitys:

  • ignorante: Todos os tipos de referência são anuláveis quando o contexto de anotação está desativado.
  • nonnullable: um tipo de referência não anotado, C não é anulável quando o contexto de anotação está habilitado.
  • nullable: Um tipo de referência anotado, C?, é anulável, mas um aviso pode ser emitido quando o contexto de anotação está desativado. As variáveis declaradas com var são anuláveis quando o contexto de anotação está habilitado .

O compilador gera avisos com base nessa anulabilidade:

  • Tipos não anuláveis causam avisos se um valor potencial null for atribuído a eles.
  • Tipos anuláveis causam avisos se forem desreferenciados quando talvez-nulo.
  • Tipos alheios causam avisos se forem desreferenciados quando maybe-null e o contexto de aviso estiver habilitado.

Cada variável tem um estado anulável padrão que depende de sua anulabilidade:

  • As variáveis anuláveis têm um estado nulo padrão de talvez-nulo.
  • As variáveis não anuláveis têm um estado nulo padrão de não-nulo.
  • As variáveis alheias anuláveis têm um estado nulo padrão de não-nulo.

Antes de habilitar tipos de referência anuláveis, todas as declarações em sua base de código são anuláveis ignorantes. Isso é importante porque significa que todos os tipos de referência têm um estado nulo padrão de não-nulo.

Avisos de endereço

Se o seu projeto usa o Entity Framework Core, você deve ler as orientações sobre como trabalhar com tipos de referência anuláveis.

Ao iniciar a migração, você deve começar habilitando apenas os avisos. Todas as declarações permanecem anuláveis ignorando, mas você verá avisos quando cancelar a referência de um valor após suas alterações de estado nulo para talvez-nulo. À medida que você aborda esses avisos, você verificará o nulo em mais locais e sua base de código se tornará mais resiliente. Para aprender técnicas específicas para diferentes situações, consulte o artigo sobre Técnicas para resolver avisos anuláveis.

Você pode endereçar avisos e habilitar anotações em cada arquivo ou classe antes de continuar com outro código. No entanto, muitas vezes é mais eficiente lidar com os avisos gerados enquanto o contexto é avisos antes de ativar as anotações de tipo. Dessa forma, todos os tipos ficam alheios até que você tenha abordado o primeiro conjunto de avisos.

Ativar anotações de tipo

Depois de abordar o primeiro conjunto de avisos, você pode habilitar o contexto de anotação. Isso altera os tipos de referência de ignorantes para não anuláveis. Todas as variáveis declaradas com var são anuláveis. Esta alteração introduz frequentemente novos avisos. A primeira etapa para abordar os avisos do compilador é usar ? anotações nos tipos de parâmetro e retorno para indicar quando os argumentos ou valores de retorno podem ser null. Ao realizar essa tarefa, seu objetivo não é apenas corrigir avisos. O objetivo mais importante é fazer com que o compilador entenda sua intenção para valores nulos potenciais.

Os atributos estendem as anotações de tipo

Vários atributos foram adicionados para expressar informações adicionais sobre o estado nulo das variáveis. As regras para suas APIs são provavelmente mais complicadas do que não-nulas ou talvez-nulas para todos os parâmetros e valores de retorno. Muitas de suas APIs têm regras mais complexas para quando as variáveis podem ou não ser null. Nesses casos, você usará atributos para expressar essas regras. Os atributos que descrevem a semântica da sua API são encontrados no artigo sobre Atributos que afetam a análise anulável.

Próximos passos

Depois de resolver todos os avisos depois de habilitar as anotações, você pode definir o contexto padrão para seu projeto como habilitado. Se você adicionou pragmas em seu código para a anotação anulável ou contexto de aviso, você pode removê-los. Com o tempo, poderá ver novos avisos. Você pode escrever código que introduz avisos. Uma dependência de biblioteca pode ser atualizada para tipos de referência anuláveis. Essas atualizações alterarão os tipos nessa biblioteca de anuláveis para não anuláveis ou anuláveis.

Você também pode explorar esses conceitos em nosso módulo Learn on Nullable safety in C#.