Operadores null de C#

Tip

Este artículo forma parte de la sección Aspectos básicos de los desarrolladores que conocen al menos un lenguaje de programación y están aprendiendo C#. Si no está familiarizado con la programación, comience primero con los tutoriales de introducción . Para obtener la referencia completa de operadores, consulte Operadores de acceso a miembros y Operadores de uso combinado de null en la referencia del lenguaje de programación.

C# proporciona varios operadores que hacen que el código seguro para valores nulos sea conciso. En lugar de anidar if (x != null) restricciones en todo el código, estos operadores le permiten expresar el acceso seguro a valores Null, los valores de reserva y las pruebas de Null en una sola expresión.

En este artículo se trata ?. y ?[] para el acceso condicional Null, ?? para el uso combinado de Null, ??= para la asignación del uso combinado de Null y is null/is not null para la coincidencia de patrones de Null.

Acceso a miembros condicionales Null ?.

El ?. operador accede a un miembro solo cuando el objeto no es NULL. Cuando el objeto es null, la expresión completa se evalúa a null en lugar de lanzar un NullReferenceException.

string? name = null;

// Without ?., accessing a member on null throws NullReferenceException:
// int len = name.Length; // throws if name is null

// ?. returns null instead of throwing:
int? len = name?.Length;
Console.WriteLine(len.HasValue); // False

name = "C#";
Console.WriteLine(name?.Length); // 2

El operador ?. genera un cortocircuito: cuando el lado izquierdo es null, se omite todo lo que está a la derecha. No se ejecutan llamadas a métodos y no se producen efectos secundarios.

Puede encadenar varios ?. operadores en una sola expresión. La cadena se detiene en el primer null que encuentra.

string? input = null;

// Chain ?. across multiple method calls — short-circuits at the first null:
string? upper = input?.Trim()?.ToUpperInvariant();
Console.WriteLine(upper ?? "(none)"); // (none)

input = "  hello  ";
Console.WriteLine(input?.Trim()?.ToUpperInvariant()); // HELLO

Acceso a índices condicionales nulos ?[]

El operador ?[] aplica el mismo comportamiento de cortocircuito al indexador y al acceso de matriz. Úselo cuando la propia colección podría ser null:

string[]? tags = null;

// ?[] accesses an element only when the collection is non-null
string? first = tags?[0];
Console.WriteLine(first ?? "(none)"); // (none)

tags = ["csharp", "dotnet", "nullable"];
Console.WriteLine(tags?[0]);          // csharp

Operadores condicionales Null de cadena

Encadene varios ?. operadores para recorrer una ruta de referencias potencialmente nulas. La cadena produce un cortocircuito en el primero null:

var order = new Order("ORD-001", null);

// Each ?. short-circuits when null: Customer is null, so Address and City are never accessed
string? city = order.Customer?.Address?.City;
Console.WriteLine(city ?? "(no city)"); // (no city)

var fullOrder = new Order("ORD-002",
    new Customer("Alice", new Address("123 Main St", "Springfield", "IL")));

Console.WriteLine(fullOrder.Customer?.Address?.City); // Springfield

Cuando Customer es null, ni Address ni City se evalúan. La expresión completa devuelve null.

Invocación de delegado seguro para subprocesos

?. ofrece una forma sencilla y segura para subprocesos de invocar un delegado o generar un evento. La expresión de delegado solo se evalúa una vez, por lo que no hay ninguna ventana para que otro subproceso cancele la suscripción entre la comprobación nula y la invocación:

EventHandler? clicked = null;

// No subscribers — ?.Invoke does nothing instead of throwing NullReferenceException
clicked?.Invoke(null, EventArgs.Empty);

clicked += (_, _) => Console.WriteLine("Button clicked!");

// With a subscriber — ?.Invoke calls the handler
clicked?.Invoke(null, EventArgs.Empty);
// Output: Button clicked!

Este patrón reemplaza la expresión anterior if (clicked != null) clicked(...) .

Uso combinado de Null en ??

El operador ?? devuelve su operando izquierdo cuando no es Null y su operando derecho cuando el izquierdo es null. Úselo para proporcionar un valor predeterminado:

string? username = null;

// ?? returns the right-hand value when the left-hand is null
string display = username ?? "Guest";
Console.WriteLine(display); // Guest

username = "alice";
display  = username ?? "Guest";
Console.WriteLine(display); // alice

?? es asociativo a la derecha, por lo que a ?? b ?? c se evalúa como a ?? (b ?? c). El primer valor distinto de NULL gana. Un patrón común consiste en encadenar ?. con ??: use ?. para atravesar de forma segura una cadena posible con valores nulos y, a continuación, ?? para sustituir un valor predeterminado si la cadena devolvió null. Para obtener un ejemplo completo, vea Combinar operadores NULL.

Asignación de uso combinado de Null ??=

El ??= operador asigna el valor derecho a una variable solo cuando la variable es null. Úselo para la inicialización diferida:

List<string>? cache = null;

// ??= assigns only when the variable is null
cache ??= LoadData();
Console.WriteLine(cache.Count); // 3

// cache is already non-null, so LoadData() isn't called again
cache ??= LoadData();
Console.WriteLine(cache.Count); // 3

static List<string> LoadData() => ["alpha", "beta", "gamma"];

Solo se evalúa la expresión de la derecha cuando la variable es null. Cuando la variable ya tiene un valor, el lado derecho no se evalúa en absoluto.

Asignación condicional Null (C# 14)

A partir de C# 14, puede usar ?. y ?[] como destinos de asignación. La asignación solo se ejecuta cuando el objeto izquierdo no es NULL:

AppConfig? config = new AppConfig();

// Assigns only when config is non-null (C# 14)
config?.Theme = "dark";
Console.WriteLine(config?.Theme); // dark

AppConfig? missing = null;
missing?.Theme = "light";                         // no-op: missing is null
Console.WriteLine(missing?.Theme ?? "(no config)"); // (no config)

El lado derecho solo se evalúa cuando se sabe que el lado izquierdo no es nulo.

Coincidencia de patrones Null: is null y is not null

Los is null patrones y is not null comprueban si una expresión es null:

string? input = null;

// is null is the preferred test — unaffected by operator overloading
if (input is null)
{
    Console.WriteLine("No input provided.");
}

// == null also works, but a custom == operator can change its behavior
if (input == null)
{
    Console.WriteLine("Still no input.");
}

Se prefiere is null sobre == null para las comprobaciones nulas. El == operador se puede sobrecargar, lo que significa que x == null puede devolver true incluso si x no es null, cuando el tipo define un operador de igualdad personalizado. El is null patrón siempre prueba la referencia nula real, independientemente de la sobrecarga del operador.

string? value = "hello";

if (value is not null)
{
    Console.WriteLine(value.ToUpper()); // HELLO
}

Combinar operadores NULL

En la práctica, a menudo se combinan varios de estos operadores. Una expresión puede atravesar de forma segura un gráfico de objetos profundos, aplicar una alternativa y, a continuación, proteger el resultado.

Order? order = GetPendingOrder();

// Chain ?. for safe traversal, ?? for a fallback, is null for a clear guard
string city = order?.Customer?.Address?.City ?? "unknown";

if (order is null)
{
    Console.WriteLine("No pending order.");
}
else
{
    Console.WriteLine($"Shipping to: {city}");
}
// Output: No pending order.

Operador null-forgiving !

El operador postfix de ! suprime las advertencias que aceptan valores Null. Anexe ! para indicar al compilador "esta expresión no es definitivamente null". El operador no tiene ningún efecto en tiempo de ejecución. Solo afecta al análisis de estado NULL del compilador.

string? name = FindUser("alice");

// Use ! only when you have information the compiler doesn't.
// FindUser guarantees a non-null result for known usernames.
int length = name!.Length;
Console.WriteLine(length); // 5

Use ! con moderación y solo cuando tenga información que el compilador no tenga. Entre los ejemplos se incluyen las pruebas que pasan de forma intencionada null para validar la lógica de comprobación de argumentos o llaman a un método cuyo contrato garantiza que no se devuelva Null dada una entrada conocida. El uso excesivo de ! derrota el propósito de los tipos de referencia anulables. Para obtener una explicación completa, consulte Tipos de referencia que aceptan valores NULL.

Consulte también