0Pricing
C# Academy · Aula

Anotações: ?, !, MaybeNull e NotNull

Use ? para tipos anuláveis, ! para suprimir avisos de nulo e atributos como MaybeNull e NotNullWhen para uma análise precisa do fluxo.

Anotações: ?, !, MaybeNull e NotNull é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.

Além de ? e !: atributos de anulabilidade

A anotação básica ? e a verificação de nulo resolvem a maioria dos casos, mas alguns padrões exigem anotações mais expressivas. O namespace System.Diagnostics.CodeAnalysis fornece atributos que dão ao compilador uma visão mais aprofundada do fluxo de nulidade.

MaybeNull e NotNull

[MaybeNull] informa ao compilador que um tipo de retorno não anulável pode, na prática, ser nulo (por exemplo, em um método genérico). [NotNull] garante que um parâmetro anulável não será nulo após a chamada.

using System.Diagnostics.CodeAnalysis;

// [MaybeNull]: return might be null even though T is non-nullable
[return: MaybeNull]
public T Find<T>(int id)
{
    // Returns default(T) which is null for reference types
    return _cache.TryGetValue(id, out var val) ? val : default!;
}

// [NotNull]: after this call, output is guaranteed non-null
public static void EnsureNotNull<T>(
    [NotNull] ref T? value,
    T defaultValue) where T : class
{
    value ??= defaultValue;
}

NotNullWhen: não nulo condicionalmente

[NotNullWhen(true)] informa ao compilador que um parâmetro de saída não é nulo quando o método retorna true. É assim que o padrão TryParse é anotado.

using System.Diagnostics.CodeAnalysis;

public static bool TryParseEmail(
    string? input,
    [NotNullWhen(true)] out string? email)
{
    if (input?.Contains('@') == true)
    {
        email = input.Trim().ToLower();
        return true;
    }
    email = null;
    return false;
}

// Usage — no warning after true check:
if (TryParseEmail(raw, out var email))
    Console.WriteLine(email.Length); // safe — email is non-null here

MaybeNullWhen: nulo condicionalmente

[MaybeNullWhen(false)] é o inverso — a saída pode ser nula quando o método retorna false. É usado em padrões de dicionário com TryGetValue.

// This is how Dictionary<K,V>.TryGetValue is annotated:
public bool TryGetValue(
    TKey key,
    [MaybeNullWhen(false)] out TValue value)
{ ... }

// Usage:
if (!dict.TryGetValue("key", out var value))
    return; // early return — value is null in this branch

Console.WriteLine(value.Length); // safe after the guard

AllowNull e DisallowNull

[AllowNull] em uma propriedade não anulável permite que os chamadores passem nulo para ela (por exemplo, um setter que converte nulo em uma cadeia de caracteres vazia). [DisallowNull] proíbe nulo em um tipo anulável.

public class Config
{
    private string _name = "";

    // Allow setting null (setter converts null -> empty)
    [AllowNull]
    public string Name
    {
        get => _name;
        set => _name = value ?? "";
    }

    // Getter always returns non-null: fine
    // Setter accepts null: [AllowNull] tells compiler that's OK
}

NotNullIfNotNull: propagando a anulabilidade

[NotNullIfNotNull(paramName)] diz: se o parâmetro X não for nulo, o valor de retorno também não será nulo. É útil para funções de transformação.

[return: NotNullIfNotNull(nameof(value))]
public static string? Normalize(string? value)
{
    return value?.Trim().ToLower();
}

// Usage:
string  name = "  Alice  ";
string  norm1 = Normalize(name)!; // guaranteed non-null
string? raw   = GetRaw();
string? norm2 = Normalize(raw);   // still nullable (raw might be null)

DoesNotReturn

[DoesNotReturn] marca um método que sempre lança uma exceção. O compilador sabe que o código após a chamada é inacessível, suprimindo avisos de nulidade espúrios.

using System.Diagnostics.CodeAnalysis;

[DoesNotReturn]
public static void ThrowNotFound(int id)
    => throw new KeyNotFoundException($"Entity {id} not found");

// Usage — no null warning after the call:
var order = _db.Orders.Find(id);
if (order is null) ThrowNotFound(id);

Console.WriteLine(order.Id); // no CS8602 — compiler knows ThrowNotFound threw

MemberNotNull: pós-condição em campos

[MemberNotNull] informa ao compilador que um método garante que determinados campos não serão nulos após seu retorno. É útil para auxiliares de inicialização tardia.

public class DataLoader
{
    private string? _data;

    [MemberNotNull(nameof(_data))]
    private void EnsureLoaded()
    {
        if (_data is null)
            _data = LoadFromFile();
    }

    public string GetData()
    {
        EnsureLoaded();
        return _data; // no CS8603 — compiler knows _data is set
    }
}

Combinando anotações

Os atributos podem ser combinados para criar contratos de API precisos. Veja um auxiliar de validação encadeável que combina vários atributos.

public static class Guard
{
    [return: NotNull]
    public static T NotNull<T>(
        [NotNull][AllowNull] T? value,
        [CallerArgumentExpression(nameof(value))] string? name = null)
        where T : class
    {
        ArgumentNullException.ThrowIfNull(value, name);
        return value;
    }
}

// Usage:
var product = Guard.NotNull(await _repo.FindAsync(id));
Console.WriteLine(product.Name); // no warning

Operadores de nulo: ?. ?? ??=

Os operadores condicional de nulo (?.), de coalescência de nulo (??) e de atribuição por coalescência de nulo (??=) permitem escrever código conciso e seguro contra nulos, sem verificações if extensas.

string? name = GetName();

// ?. safe navigation
int? len = name?.Length;
string? upper = name?.ToUpper().Trim();

// ?? default value
string display = name ?? "Anonymous";

// ??= lazy init
name ??= "Default";

// Chaining
string result = user?.Profile?.DisplayName ?? user?.Name ?? "Guest";

Verificação rápida

O que [NotNullWhen(true)] em um parâmetro de saída informa ao compilador?

Recapitulação: anotações de anulabilidade

Principais conclusões:

  • [NotNullWhen(true)]: padrão TryParse — não nulo quando o retorno é true
  • [MaybeNull]: um tipo não anulável ainda pode retornar nulo (padrões genéricos)
  • [DoesNotReturn]: o método sempre lança uma exceção — o código posterior é inacessível
  • [MemberNotNull]: o método garante que os campos estejam definidos após seu retorno
  • ?., ??, ??=: navegação segura contra nulos e valores padrão de forma concisa

Perguntas Frequentes

A aula “Anotações: ?, !, MaybeNull e NotNull” é grátis?

Sim — o texto completo de “Anotações: ?, !, MaybeNull e NotNull” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.

O que vou aprender em “Anotações: ?, !, MaybeNull e NotNull”?

Use ? para tipos anuláveis, ! para suprimir avisos de nulo e atributos como MaybeNull e NotNullWhen para uma análise precisa do fluxo. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar C# Academy?

Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Anotações: ?, !, MaybeNull e NotNull”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de C# Academy?

Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Ativação e compreensão de NRT
  2. Anotações: ?, !, MaybeNull e NotNull
  3. Operadores condicionais e de coalescência de nulo
  4. Migrando uma base de código para NRT
← Voltar para C# Academy