Segurança nula em C#

Dica

Este artigo faz parte da seção Conceitos Básicos para desenvolvedores que já conhecem pelo menos uma linguagem de programação e estão aprendendo C#. Se você é novo em programação, comece com os tutoriais Comece agora.

Vindo de Java ou C++? O C# fornece segurança nula em tempo de compilação por meio de tipos de referência anuláveis. A meta é semelhante às anotações @NonNull de Java, mas impostas pelo compilador. O C# também tem operadores dedicados como ?. e ?? que tornam concisas expressões de segurança nula.

null representa a ausência de um valor. Quando você tenta acessar um membro em uma referência null, chamando um método ou lendo uma propriedade, o tempo de execução lança um NullReferenceException:

// Accessing a member on null throws NullReferenceException at runtime:
// string? name = null;
// int length = name.Length; // throws NullReferenceException

// Check before you dereference:
string? name = null;
if (name is not null)
{
    Console.WriteLine($"Name has {name.Length} characters.");
}
else
{
    Console.WriteLine("Name has no value.");
}
// Output: Name has no value.

O C# oferece três ferramentas complementares para escrever código nulo seguro:

  • Tipos de valor anuláveis: que permitem a um tipo de valor, como int ou bool, também armazenar null
  • Tipos de referência anuláveis: permitem que o compilador acompanhe se uma referência pode ser null
  • Operadores nulos: expressam acesso null-safe e lógica de fallback de forma concisa

Tipos de valor anuláveis

Tipos de valor, como int, doublee bool não podem manter null por padrão. Adicione ? ao nome do tipo para criar um tipo de valor anulável que contém um valor ou null:

int? score = null;
Console.WriteLine(score.HasValue);               // False

score = 95;
Console.WriteLine(score.HasValue);               // True
Console.WriteLine(score.GetValueOrDefault());    // 95

int? missing = null;
Console.WriteLine(missing.GetValueOrDefault(-1)); // -1

Tipos de valor anuláveis são úteis quando um tipo de valor subjacente precisa representar "sem dados". Cenários comuns incluem colunas de banco de dados que podem estar ausentes, configurações opcionais de configuração e leituras de sensor que ainda não foram capturadas.

Para obter a cobertura completa da declaração, verificação e conversão, consulte tipos de valor anuláveis.

Tipos de referência anuláveis

Tipos de referência, como string, matrizes e instâncias de classe, podem conter null no tempo de execução. Tipos de referência anuláveis são um recurso do compilador que torna a intenção nula explícita e captura erros em tempo de compilação.

Usando a ? anotação, você declara sua intenção:

  • string? — essa referência pode ser null; o compilador avisa se você a desreferenciar sem verificar primeiro
  • string — essa referência não deve ser null; o compilador avisará se você atribuir null a ela
// string?  means this reference might be null
// string   means this reference should not be null
string? nullableName = null;
string  nonNullName  = "Alice";

// ?. safely accesses a member when the reference might be null
string display = nullableName?.ToUpper() ?? "(no name)";
Console.WriteLine(display);         // (no name)

display = nonNullName.ToUpper();    // safe: nonNullName is never null
Console.WriteLine(display);         // ALICE

Todos os projetos .NET que os modelos de SDK modernos criam habilitam tipos de referência anuláveis por padrão. Para obter diretrizes completas sobre como habilitar e anotar, consulte tipos de referência anuláveis.

Operadores nulos

O C# inclui vários operadores que permitem gravar um código null-safe sem guardas manuais ifnulas em todos os lugares:

Operador Name Purpose
?. Acesso de membro condicional nulo Acessar um membro somente quando o objeto não for nulo
?[] Acesso de indexador condicional nulo Acessar um elemento somente quando a coleção não for nula
?? Coalescência nula Retornar um valor de fallback quando a expressão for null
??= Atribuição de coalescência nula Atribuir somente quando a variável for null
is null / is not null Padrão nulo Teste nulo preferencial
string? city = GetCity();

// ?. — access a member only when non-null
int? len = city?.Length;

// ?? — substitute a default when null
string display = city ?? "unknown";

// is null — preferred null test
if (city is null)
{
    Console.WriteLine("No city provided.");
}
else
{
    Console.WriteLine($"{display} ({len} chars)");
}
// Output: No city provided.

Para obter exemplos detalhados de cada operador, consulte operadores Null.

Tipos de valor anuláveis e tipos de referência anuláveis atendem a diferentes finalidades

Tipos de valor anuláveis e tipos de referência anuláveis não são alternativas. Eles resolvem problemas diferentes:

  • Use T? para um tipo de valor que precisa representar "sem valor". Por exemplo, use int? para uma coluna de banco de dados opcional ou DateTime? para um evento que ainda não está agendado.
  • Use string? e outras anotações de referência anuláveis para documentar que uma referência pode ser null, para que o compilador possa avisá-lo antes que ocorra um NullReferenceException durante o tempo de execução.

Juntos, esses recursos e os operadores nulos fornecem um conjunto completo de ferramentas para gravar código C# nulo.