0Pricing
C# Academy · Lección

Anotaciones: ?, !, MaybeNull y NotNull

Use ? para tipos nullable, ! para suprimir advertencias de nulabilidad y atributos como MaybeNull y NotNullWhen para un análisis de flujo preciso.

Anotaciones: ?, !, MaybeNull y NotNull es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.

Más allá de ? y !: atributos de nulabilidad

La anotación básica ? y la comprobación de null resuelven la mayoría de los casos, pero algunos patrones requieren anotaciones más expresivas. El espacio de nombres System.Diagnostics.CodeAnalysis proporciona atributos que ofrecen al compilador una visión más profunda del flujo de nulabilidad.

MaybeNull y NotNull

[MaybeNull] indica al compilador que un tipo de retorno no anulable puede ser null en la práctica (por ejemplo, un método genérico). [NotNull] garantiza que un parámetro anulable no será null después de la llamada.

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: no nulabilidad condicional

[NotNullWhen(true)] indica al compilador que un parámetro de salida no es null cuando el método devuelve true. Así se anota el patrón estándar de TryParse.

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: nulabilidad condicional

[MaybeNullWhen(false)] es la inversa: la salida puede ser null cuando el método devuelve false. Se utiliza en los patrones de diccionario 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 y DisallowNull

[AllowNull] en una propiedad no anulable permite que los llamadores le pasen null (por ejemplo, un establecedor que convierte null en una cadena vacía). [DisallowNull] prohíbe null en un tipo anulable.

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: propagación de la nulabilidad

[NotNullIfNotNull(paramName)] indica lo siguiente: si el parámetro X no es null, el valor devuelto tampoco es null. Resulta útil para funciones de transformación.

[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 un método que siempre produce una excepción. El compilador sabe que el código posterior a la llamada es inalcanzable y suprime las advertencias de nulabilidad espurias.

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: condición posterior sobre campos

[MemberNotNull] indica al compilador que un método garantiza que determinados campos no serán null después de que el método devuelva el control. Resulta útil para auxiliares de inicialización diferida.

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
    }
}

Combinación de anotaciones

Los atributos se pueden combinar para definir contratos de API precisos. Este es un auxiliar de validación fluido que combina varios 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 null: ?. ?? ??=

Los operadores condicional de null (?.), de coalescencia de null (??) y de asignación con coalescencia de null (??=) permiten escribir código conciso y seguro frente a null sin comprobaciones 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";

Comprobación rápida

¿Qué le indica al compilador [NotNullWhen(true)] aplicado a un parámetro out?

Resumen: anotaciones de nulabilidad

Conclusiones clave:

  • [NotNullWhen(true)]: patrón TryParse: no es null cuando devuelve true
  • [MaybeNull]: un tipo no anulable aún puede devolver null (valores predeterminados genéricos)
  • [DoesNotReturn]: el método siempre produce una excepción; el código posterior es inalcanzable
  • [MemberNotNull]: el método garantiza que los campos se establezcan antes de devolver el control
  • ?., ??, ??=: navegación y valores predeterminados concisos y seguros frente a null

Preguntas frecuentes

¿La lección «Anotaciones: ?, !, MaybeNull y NotNull» es gratis?

Sí — el texto completo de «Anotaciones: ?, !, MaybeNull y NotNull» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Anotaciones: ?, !, MaybeNull y NotNull»?

Use ? para tipos nullable, ! para suprimir advertencias de nulabilidad y atributos como MaybeNull y NotNullWhen para un análisis de flujo preciso. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «Anotaciones: ?, !, MaybeNull y NotNull»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Activación y comprensión de NRT
  2. Anotaciones: ?, !, MaybeNull y NotNull
  3. Operadores null-conditional y null-coalescing
  4. Migración de una base de código a NRT
← Volver a C# Academy