CodeGym /Cursos /C# SELF /Análise de avisos do compilador

Análise de avisos do compilador

C# SELF
Nível 14 , Lição 4
Disponível

1. Introdução

Imagina que o código é uma peça de teatro e as variáveis são os atores. Toda vez que uma variável entra numa nova cena (bloco de código), ela pode estar "viva" (tem valor) ou ser um "fantasma" (null). Só que tem um detalhe: o espectador — o compilador — assiste a peça só pelo roteiro. Ele vê onde os atores ganham papéis (recebem valores) e onde eles somem (viram null). Mas ele não consegue ver a realidade (execução do programa) — só pode imaginar pelo texto do roteiro!

Análise estática de fluxo de dados é o processo onde o compilador checa o código antes de rodar o programa, pra sacar se alguém vai tentar fazer uma cena com "queda de NullReferenceException".

Como funciona

A partir do C# 8.0 e do modo Nullable Reference Types (NRT), o compilador analisa se uma variável pode virar null em algum caminho do código. Se sim — ele já te avisa. Ele não deixa você "usar o nome de um ator que virou fantasma do nada".

2. Como ler os avisos do compilador

Principais categorias de avisos

Quando o modo NRT tá ligado, o compilador fica de olho principalmente nas variáveis de referência (string, User, arrays, objetos). Olha só os tipos de avisos mais comuns:

  • Possible null assignment — você tá tentando atribuir um valor que pode ser null pra uma variável que não aceita null.
  • Dereference of a possibly null reference — você acessou um membro de um objeto, mas o compilador acha que ele pode ser null.
  • Possible null return — o método pode retornar null, mesmo que pela assinatura ele deveria devolver um valor.
  • Nullable object must have a value — você usou .Value num tipo nullable sem checar antes.
  • Unassigned non-nullable property — você não atribuiu valor pra um campo/propriedade que não aceita null.

Normalmente, na IDE (tipo Rider ou Visual Studio), esses avisos aparecem sublinhados com uma linha ondulada, e se passar o mouse aparece uma explicação.

Exemplo de aviso típico


#nullable enable

string? possibleNull = GetString();

// Opa, o compilador reclama: "Dereference of a possibly null reference"
int length = possibleNull.Length; // Aviso!

O compilador não tem certeza se possibleNull não é null, então acessar .Length pode dar exceção.

Se o método for assim:

string? GetString() { ... }

E você faz:

string nonNullable = GetString();

Vai rolar aviso: possível atribuição insegura de null pra variável non-nullable.

3. O compilador analisa seu código

Exemplo 1: atribuição direta


string? name = null;
Console.WriteLine(name.Length); // Aviso: possível acesso a null

Aqui é na cara: name é null, então tentar acessar a propriedade é perigoso.

Exemplo 2: checando null


string? name = GetUserName();

if (name != null)
{
    Console.WriteLine(name.Length); // Suave!
}
else
{
    Console.WriteLine("Nome não informado!");
}

O compilador entende que dentro do bloco if (name != null) a variável tá segura. Isso é o flow analysis — análise do fluxo de valores dependendo das condições.

4. O compilador não enxerga "dentro do método"

Ele só olha pra assinatura — se tá escrito que o método retorna string?, ele acredita que pode ser null, mesmo que lá dentro sempre retorne uma string.

Exemplo 3: retorno de valor de método


string? GetMaybeName(bool useName)
{
    if (useName)
        return "Code Jedi";
    else
        return null;
}

void PrintLength()
{
    string? name = GetMaybeName(false);

    Console.WriteLine(name.Length); // Aviso!
}

O compilador vê que GetMaybeName pode retornar null, então pede pra você tomar cuidado.

5. Cenários comuns e avisos

Atribuindo nullable em variável non-nullable


string? maybeUser = GetUser();
string alwaysUser = maybeUser; // aviso: possible null assignment

Pra resolver o aviso:


string alwaysUser = maybeUser ?? "Convidado";

Agora sempre vai ter uma string — ou do método, ou "Convidado".

Esqueceu de checar .HasValue em value-type nullable


int? age = GetAge();
int realAge = age.Value; // aviso: possível acesso a null

Tem que fazer assim:


if (age.HasValue)
    Console.WriteLine(age.Value);

Ou assim:


int realAge = age ?? -1;

Propriedades automáticas sem inicialização


class User
{
    public string Name { get; set; } // aviso: não inicializado!
}

Soluções:


public string Name { get; set; } = "Sem nome";

ou


public string? Name { get; set; }

6. Casos complicados de análise de fluxo

Análise em loops


string? text = null;

while (text == null)
{
    text = Console.ReadLine();
}

Console.WriteLine(text.Length); // tudo certo: o compilador entendeu!

Caminhos diferentes de atribuição


string? name;
if (Random.Shared.Next() % 2 == 0)
    name = "Alice";
else
    name = null;

Console.WriteLine(name.Length); // aviso: possible null dereference

O compilador analisa todos os caminhos. Se em pelo menos um deles for null — ele avisa.

7. Como "acalmar" o compilador (e quando não fazer isso)

Às vezes você tem certeza que o valor não pode ser null, mas o compilador não acredita:


string? value = GetSomething();
if (value == null)
    throw new Exception("Esperado valor!");

Console.WriteLine(value.Length); // Aviso sumiu

Ou você usa o operador !:


string? value = GetSomething();
Console.WriteLine(value!.Length); // Sem avisos, mas perigoso

Isso se chama null-forgiving operator. Ele não checa nada — só fala pro compilador: "relaxa, tá tudo sob controle". Só que se você errar — vai tomar exceção em runtime.

2
Tarefa
C# SELF, nível 14, lição 4
Bloqueado
Verificação de null antes de usar uma variável
Verificação de null antes de usar uma variável
2
Tarefa
C# SELF, nível 14, lição 4
Bloqueado
Eliminando avisos usando o operador de coalescência nula
Eliminando avisos usando o operador de coalescência nula
1
Pesquisa/teste
Tipos Nullable, nível 14, lição 4
Indisponível
Tipos Nullable
Introdução aos Nullable Reference Types
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION