![]() |
Hoje vamos recordar os conceitos relacionados com a palavra-chave Null, os tipos Nullable Value, os tipos Nullable Reference, o operador Null Coalescing e o operador Null-Conditional. |
As nulabilidades dos tipos
Qualquer tipo de referência pode ter um dos seguintes valores quanto a nulidade que descreve quando os avisos são gerados:
![]() |
Nonnullabe ou Não anulável: Null ou nulo não pode ser atribuído a variáveis desse tipo. Variáveis desse tipo não precisam ser verificadas quanto a nulidade (ser igual a null) antes de serem desreferenciadas;
Nullabe ou Anulável: Null ou nulo pode ser atribuído a variáveis deste tipo. Desfazer a referência das variáveis desse tipo sem primeiro verificar se há null ou nulo vai causar um aviso;
Oblivious:
Oblivious é o estado pré-C# 8.0. Variáveis desse tipo podem ser
referenciadas ou atribuídas sem avisos;
Uknown ou Desconhecido: Desconhecido
geralmente é usado para parâmetros de tipo em que as restrições não informam ao
compilador que o tipo deve ser anulável ou não anulável.;
A nulidade de um tipo em uma declaração de variável é controlada pelo contexto
anulável em que a variável for declarada.
A seguir vamos recordar o comportamento dos Nulls, começando com a palavra-chave Null.
1- Null Keyword
A palavra-chave null é usada para representar
uma referência nula, que é uma referência que não se
refere(nossa...) a nenhum objeto. Ela só pode ser atribuída a variáveis
de tipo de referência e não para variáveis de tipo de valor.
string s = null;
Tentar acessar um objeto que tem uma referência a null
causará uma exceção, porque não há instância válida para desfazer a
referência.
int tamanho = lado.Length;
// erro: NullReferenceException
A fim de acessar com segurança os membros da instância de um objeto que pode
ser null, a primeira coisa a fazer é
verificar se existe uma referência nula.
Este teste pode ser feito, por exemplo, usando o operador igual a (==) :
using System;
namespace CShpNulls
{
class Program
{
static void Main(string[] args)
{
Teste teste = new Teste();
if (teste.lado == null)
{
// cria um objeto valido(string vazia)
teste.lado = "";
}
int tamanho = teste.lado.Length; // 0
Console.ReadKey();
}
}
class Teste
{
public string lado;
}
}
|
No método Main criamos uma instância da classe Teste e a seguir verificamos se o campo lado é null usando o operador ==.
Outra opção é usar o operador ternário (? :) para atribuir um valor adequado no caso de um null for encontrado para a string:
string lado = null;
int tamanho = (lado != null) ?
lado.Length : 0; //
(se lado for diferente de null
atribui o tamanho senão atribui zero)
2- Nullabe Value Types
Um tipo de valor
pode ser feito para tratar o valor null além de seu
intervalo normal de valores anexando um ponto de interrogação (?) ao seu tipo
subjacente. Ex: int?
Isso é chamado de tipo anulável ou Nullable Value,
e permite os tipos simples, bem como tipos struct,
para indicar um valor indefinido.
Por exemplo, bool? é um tipo anulável que pode conter os valores true, false e null.
3- Nullabe Reference Types
Um dos erros mais comuns nas linguagens do paradigma da programação orientada a objetos é desfazer a referencia uma variável definida como nula, o que causa uma exceção de referência nula.
Para ajudar a evitar esse problema, o C# 8.0 introduziu um distinção entre tipos de referência anuláveis e não anuláveis.
Assim da mesma forma que os tipos de valor anuláveis, um tipo de referência anulável é criado anexando um ponto de interrogação (?) para o tipo e dessa forma apenas a esse tipo de referência pode ser atribuiu o valor null.
string? s1 = null;
// tipo de referência anulável ou nullable
reference type
string s2 = "";
// tipo de referência não anulável ou non-nullable
reference type
Este recurso precisa ser explicitamente ativado porque existem os tipos de
referência que então se tornam tipos de referência não anuláveis.
Para habilitar o recurso em todo o projeto, clique com o botão direito do mouse
no item do projeto no Solution Explorer e
selecione Editar Arquivo de Projeto no menu de
contexto para abrir o arquivo .csproj.
Neste arquivo, adicione um elemento Nullable ao elemento PropertyGroup e defina seu valor para enable:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
|
Outras configurações válidas são :
warnings : O contexto de anotação anulável
está desativado. O contexto de aviso anulável está ativado. Variáveis de um
tipo de referência são esquecidas. Todos os avisos de anulação estão
habilitados.
annotations: O contexto de anotação anulável
está ativado. O contexto de aviso anulável está desativado. Variáveis de um
tipo de referência, string por exemplo, não são anuláveis. Todos os avisos de
anulação são desativados.
disable: O contexto de anotação anulável
está desativado. O contexto de aviso anulável está desativado. As variáveis de
um tipo de referência são esquecidas, assim como as versões anteriores do C#.
Todos os avisos de anulação são desativados.
Como alternativa,
o recurso pode ser habilitado para apenas um único arquivo adicionando a
diretiva #nullable enable a esse arquivo.
Uma vez ativado, qualquer atribuição de null a
tipos de referência não anuláveis irá desencadear um alerta de
compilação ou warning.
Ex:
#nullable enable
string a = null; // Atenção
Agora, os tipos de referência não anuláveis não precisam ser verificados para valores nulos antes eles de serem desreferenciados.
Tentar remover a referência de uma referência anulável em contextos quando o valor pode ser um null causará um aviso do compilador, e, para remover o aviso é preciso realizar uma verificação de valor null.
Este comportamento pode ser substituído usando o operador null-forgiving (!) adicionado no C# 8.0.
Nos casos em que o compilador não poder determinar que uma variável não é nula, este operador postfix pode ser usado para suprimir o aviso quando você tiver certeza de que a variável anulável não está definida como nula.
#nullable enable string? d = "Olá"; //... int a = d.Length; // alerta int b = d!.Length; // sem alerta |
4-
Null-Coalescing Operator
O operador de coalescência nula (??)
retorna o operando à esquerda se for não nulo e, caso contrário,
retorna o operando à direita.
Este operador condicional fornece uma sintaxe fácil para atribuir um tipo anulável a um tipo não anulável.
int? i = null; int j = i ?? 0; // atribui o valor zero |
Agora, uma variável de tipo anulável não deve ser convertida explicitamente em um tipo não anulável. Isso causará um erro de tempo de execução se a variável for nula como seu valor.
O C# 8.0 introduziu o operador de atribuição de coalescência nula (?? =), combinando o operador de coalescência nula com uma atribuição.
Este operador atribui o valor do lado direito ao operando do lado esquerdo se o operando do lado esquerdo for avaliado como nulo.
5- Null-Conditional Operator
Na versão 6.0 do C# foi introduzido o operador nulo-condicional (?.).
Este operador fornece uma maneira concisa de realizar verificações de nulos ao acessar um objeto.
Ele funciona como o operador de acesso de membro regular(.), exceto que se uma referência nula for encontrada, o valor nulo será retornado em vez de causar uma exceção.
string s = null;
int? length = s?.Length; //
atribui null
Combinar este operador com o operador de coalescência nula é útil para atribuir um valor padrão sempre que uma referência nula aparecer.
string s = null;
int length = s?.Length ?? 0;
// atribui zero
Outro uso para o
operador nulo-condicional são os arrays.
O ponto de interrogação(?) pode ser colocado antes dos colchetes([]) do array
e a expressão será avaliada como nula se o array não for inicializado:
string[] s = null;
string s3 = s?[3];
// atribui null
E estamos conversados...
"E não comuniqueis
com as obras infrutuosas das trevas, mas antes condenai-as. Porque o que eles
fazem em oculto até dizê-lo é torpe. Mas todas estas coisas se manifestam, sendo
condenadas pela luz, porque a luz tudo manifesta."
Efésios 5:11-13
Referências:
C# 8.0 - A instrução switch - Macoratti
C# - Programação Funcional - Exemplos
C# 8.0 - As novidades da nova versão
C# - Coleções Imutáveis - Macoratti
C# - O que há de novo com o C# 9.0
C# 9.0 - Apresentando Records
C# - Sintaxe e conceitos básicos
C# - Os 10 Erros mais comuns dos iniciantes
C# - Otimizando o código -