C# - Contexto de  de referência anuláveis (Nullable)


 Hoje vamos revisitar o recurso apresentando na versão 8.0 da linguagem C# - os tipos de referências anuláveis.

O C# 8.0 apresenta tipos de referência que permitem valor nulo e tipos de referência que não permitem valor nulo que permitem que você defina quais variáveis podem ser null e quais variáveis NUNCA podem ser null.

A linguagem C# sempre teve o conceito de nulo ou null no código. O null indica a ausência de um objeto, é um sinônimo de "nada" e é um conceito fácil de ser entendido pelas pessoas quando você declara uma variável.

Acontece que ao tratar com null mais cedo ou mais tarde iremos nos defrontar com a mensagem NullReferenceException que indica que houve uma tentativa de manipular um objeto que esta apontando para null.

Esse comportamento pode ser oriundo nos seguintes cenários:

No exemplo abaixo temos um exemplo bem simples onde obtemos um NullReferenceException:


O código vai lançar um NullReferenceException pois declaramos o array de strings mas não atribuímos valores e assim a variável primeiroNome será inicializada com um valor null.  E a seguir usamos o método ToLower() para tentar operar em um objeto nulo.

Nota: Quando o runtime lança uma NullReferenceException isso sempre significa a mesma coisa: você está tentando usar uma referência e a referência não foi inicializada (ou foi inicializada uma vez, mas não é mais inicializada).

Este é o tipo de erro mais comum que pode ocorrer em um código: Tentar realizar alguma operação em um objeto nulo.

Tipos de referência anuláveis

A partir do C# 8.0 podemos definir contextos dentro e ao redor dos nossos objetos onde o compilador vai executar verificações de nulidade e vai gerar avisos se formos lançar potencialmente uma NullReferenceException.

Podemos habilitar essa verificação de nulidade em um segmento de código envolvendo-o com a diretiva de pré-processador do compilador #nullable com uma configuração que indica como ele deve se comportar.

A seguir temos um exemplo usando a diretiva #nullable do pré-processador:

Estamos usando aqui dois comandos do pré-processador :

  1. #nullable enable 

  2. #nullable restore

O comando #nullable enable, diz ao compilador para verificar as variáveis que podem ter um valor null atribuído de forma indevida e acionar alertas se for o caso;

Para o exemplo as propriedades Nome e Email emitem um aviso indicando que elas precisam ser inicializadas.

 

Seguindo a orientação do compilador agora não temos mais os alertas emitidos.

Podemos usar as diretivas em outras partes do código para obter o aviso do compilador.

Agora, lembre-se que o compilador emite apenas alertas ao desenvolvedor e o código vai ser processado e não vai produzir erros.

Declarando um tipo de referência como Nullable

Também posso dizer ao compilador que está tudo bem se um desses valores de referência for atribuído como nulo anexando um ? ao final de sua declaração de variável:

Agora a propriedade Nome pode ter um valor null atribuído e mesmo estando usando a diretiva #nullable o compilador agora não emite nenhum alerta.

Verificando a nulidade em todo o projeto

E se eu quiser definir essa interação do compilador em todo o meu projeto ?

Você pode adicionar uma entrada ao seu arquivo de projeto (.csproj) que indica que a verificação anulável deve ser ativada com o elemento Nullable:

Com isso podemos remover as diretivas #nullable do pré-processador do código que vamos continuar obtendo os alertas quando pertinentes:

Desabilitando a verificação de nulidade

Da mesma forma que habilitamos podemos também desabilitar a emissão dos alertas do compilador desabilitando a verificação da nulidade.

Para isso basta usar a diretiva #nullable disable:

Na verdade existem mais opções de diretivas que podemos definir conforme mostrado a seguir:

Os avisos do compilador são apenas alertas que indicam problemas que PODEMOS ter em nosso projeto.

Você sabia que pode aumentar a importância desses avisos, convertendo-os em erros que o compilador emite e garantindo que você escreva um código melhor ?

Para isso basta adicionar o elemento TreatWarningsAsErrors ao seu arquivo de projeto e esses avisos agora passam a impedir que seu projeto seja compilado corretamente:

Agora você terá que dar maior atenção ao tratamento dos valores null no seu projeto caso contrário ele não vai compilar.

Com o .NET 6.0 os novos templates de projetos já usam a tag <Nullable> habilitando os tipos de referência a serem declarados como anuláveis caso contrário o compilador emitirá um alerta.

<PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

E estamos conversados...

"Portanto, lembrai-vos de que vós noutro tempo éreis gentios na carne, e chamados incircuncisão pelos que na carne se chamam circuncisão feita pela mão dos homens;
Que naquele tempo estáveis sem Cristo, separados da comunidade de Israel, e estranhos às alianças da promessa, não tendo esperança, e sem Deus no mundo."
Efésios 2:11,12

Referências:


José Carlos Macoratti