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 dos conceitos sobre 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 da forma como se atualiza a sua base de código, o objetivo é que os avisos sobre nulidade e as anotações sobre nulidade estejam ativados no seu projeto. Depois de atingires esse objetivo, terás a <nullable>Enable</nullable> configuração no teu projeto. Você não precisará de nenhuma das diretivas do pré-processador para ajustar as configurações em outro lugar.

Nota

Você pode designar uma Nullable configuração para seu projeto usando uma <Nullable> tag . Consulte Opções do compilador para obter mais informações.

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 valor padrão se não adicionar um Nullable elemento ao seu ficheiro 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. Ativar nullable como padrão: defina este padrão quando estiver a desenvolver ativamente novas funcionalidades. 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é-processamento ao resolver os avisos em cada ficheiro.
  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 ficheiro de código adicionado ao projeto será com suporte a anulabilidade. 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. Ativam-se os tipos de referência anuláveis à medida que se anotam as 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 nulidades:

  • 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 ao serem desreferenciados caso possam ser nulos.
  • Tipos obliviosos causam avisos se forem desreferenciados quando maybe-null e o contexto de aviso estiver ativado.

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 estadonulo 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, poderá 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. O primeiro passo para resolver os avisos do compilador é usar a anotação ? 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 disponibilizados no artigo sobre Atributos que afetam a análise de nulidade.

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 nulo indiferente para não anuláveis ou anuláveis.

Você também pode explorar esses conceitos no nosso módulo de aprendizagem sobre Nullable safety em C#.