Operador de condición nula en C#

C# 判断Sentencias de decisión en C#

En la programación en C#, manejarnullel valor es una tarea común pero propensa a errores.

Tradicionalnullel código de comprobación de null suele ser extenso y tedioso, mientras que el introducido en C# 6.0operador de condición nula(?.y?[]simplifica enormemente este proceso.

El operador de condición nula es un azúcar sintáctico introducido en C# 6.0 que permite a los desarrolladores comprobar, antes de acceder a los miembros o elementos del objeto, si el objeto esnull. Si el objeto esnull, el resultado de toda la expresión esnull, y no se lanzaráNullReferenceException。

Sintaxis básica

  • ?.- Se utiliza para acceder a miembros (propiedades, métodos, campos)
  • ?[]- Se utiliza para acceder a indexadores o elementos de matriz
Sintaxis Descripción
a?.b Siano es null, accede aa.b; de lo contrario, devuelve null
a?.Method() Siano es null, llama al método; de lo contrario, no hace nada
a?[i] Siano es null, accede al índice; de lo contrario, devuelve null

¿Por qué se necesita el operador de condición nula?

Problemas de la comprobación tradicional de null

Antes de la aparición del operador de condición nula, los desarrolladores tenían que escribir unnullcódigo de comprobación de null:

Ejemplo

// Forma tradicional: tediosas comprobaciones de null
string name = null;
if (person != null)
{
    if (person.Address != null)
    {
        if (person.Address.City != null)
        {
            name = person.Address.City.Name;
        }
    }
}

Este código no solo es extenso, sino que además es propenso a errores y tiene poca legibilidad.

Ventajas del operador de condición nula

Con el operador de condición nula, la misma lógica se puede simplificar a:

// 使用 Null 条件运算符 - 简洁明了
string name = person?.Address?.City?.Name;

Si cualquiera de los pasos en una llamada encadenada esnull, toda la expresión devolveránully no se lanzará una excepción.


Explicación detallada de la sintaxis

1. Operador de acceso a miembros?.

?.El operador se utiliza para acceder de forma segura a los miembros del objeto (propiedades, métodos, campos).

Acceso a propiedades

Ejemplo

class Person
{
    public string Name { get; set; }
    public Address Address { get; set; }
}

class Address
{
    public string City { get; set; }
}

// Acceso seguro a atributos
Person person = null;
string cityName = person?.Address?.City;  // Devuelve null, no lanza una excepción

Llamar a un método

Ejemplo

class Calculator
{
    public int Add(int a, int b) => a + b;
}

Calculator calc = null;
int? result = calc?.Add(5, 3);  // Devuelve null, no lanza una excepción

Acceso a campos

Ejemplo

class DataContainer
{
    public string Value;
}

DataContainer container = null;
string value = container?.Value;  // Devuelve null, no lanza una excepción

2. Operador de acceso a elementos?[]

?[]El operador se utiliza para acceder de forma segura a los elementos de una matriz o colección.

Acceso a elementos de una matriz

Ejemplo

int[] numbers = null;
int? firstNumber = numbers?[0];  // Devuelve null, no lanza una excepción

numbers = new int[] { 1, 2, 3 };
firstNumber = numbers?[0];  // Devolver 1

Acceso a elementos de un diccionario

Ejemplo

Dictionary<string, string> dictionary = null;
string value = dictionary?["key"];  // Devuelve null, no lanza una excepción

dictionary = new Dictionary<string, string> { ["key"] = "value" };
value = dictionary?["key"];  // Devuelve "value"

Combinación con otros operadores

Operador Nombre Uso Ejemplo Valor de retorno
? Declaración de tipos anulables Declarar un tipo de valor que puede ser null int? x = null; null
?? Operador de fusión de null Si el lado izquierdo es null, devuelve el lado derecho a ?? b b
?. Operador de condición nula Acceso seguro a miembros a?.b null o el valor de b
?[] Operador de índice de condición nula Acceso seguro a matrices o colecciones a?[i] null o el elemento
?: Operador condicional (ternario) Devuelve un valor u otro según la condición a ? b : c b o c

1. Combinación con el operador de fusión de null??combinado

El operador de condición nula se combina frecuentemente con el operador de fusión de null??para proporcionar un valor predeterminado:

Person person = null;

// 提供默认值
string cityName = person?.Address?.City ?? "未知城市";
Console.WriteLine(cityName);  // 输出: 未知城市

person = new Person { Address = new Address { City = "北京" } };
cityName = person?.Address?.City ?? "未知城市";
Console.WriteLine(cityName);  // 输出: 北京

Ejemplo

using System;

class Address
{
    public string City { get; set; }
}

class Person
{
    public string Name { get; set; }
    public Address Address { get; set; }

    public void SayHello()
    {
        Console.WriteLine($Hola, soy {Name});
    }
}

class Program
{
    static void Main()
    {
        Person person = null;

        // Acceso seguro a atributos
        Console.WriteLine(person?.Name ?? usuario sin nombre);

        // Acceder de forma segura a propiedades anidadas
        Console.WriteLine(person?.Address?.City ?? Ciudad desconocida);

        // Llamada segura a métodos
        person?.SayHello();

        // Acceso seguro a arrays
        int[] arr = null;
        Console.WriteLine(arr?[0] ?? -1);
    }
}

Salida:

未命名用户
未知城市
-1

2. Combinación con el operador condicional?:combinado

Ejemplo

Person person = null;
string displayName = person?.Name ?? (person != null ? Usuario anónimo : el usuario no existe);

3. Uso en consultas LINQ

Ejemplo

List<Person> people = new List<Person>
{
    new Person { Name = Zhang San, Address = new Address { City = Pekín } },
    new Person { Name = Li Si, Address = null },
    null
};

// Acceder de forma segura a las propiedades que pueden ser null
var cities = people
    .Where(p => p?.Address?.City != null)
    .Select(p => p.Address.City)
    .ToList();

Casos de uso prácticos

Caso 1: Enlace de datos y desarrollo de UI

Ejemplo

// Enlazar datos de forma segura en WPF o ASP.NET
public string DisplayAddress => $"{Person?.Address?.City ?? "Ciudad desconocida"} - {Person?.Address?.Street ?? "Calle desconocida"}";

// Llamar al método de forma segura
button.Click += (s, e) =>
{
    viewModel?.SaveCommand?.Execute(null);
};

Caso 2: Procesamiento de respuestas de API

Ejemplo

public class ApiResponse<T>
{
    public T Data { get; set; }
    public string Error { get; set; }
}

public class User
{
    public string Name { get; set; }
    public Profile Profile { get; set; }
}

public class Profile
{
    public string AvatarUrl { get; set; }
}

// Manejar la respuesta de API de forma segura
ApiResponse<User> response = GetUserFromApi();
string avatarUrl = response?.Data?.Profile?.AvatarUrl ?? "default-avatar.png";

Caso 3: Lectura de configuración

Ejemplo

public class AppConfig
{
    public DatabaseConfig Database { get; set; }
}

public class DatabaseConfig
{
    public string ConnectionString { get; set; }
    public int? Timeout { get; set; }
}

// Lectura segura de configuración
AppConfig config = LoadConfiguration();
string connectionString = config?.Database?.ConnectionString ?? "DefaultConnection";
int timeout = config?.Database?.Timeout ?? 30;

Precauciones y mejores prácticas

1. Tipo de valor de retorno

Al usar el operador de condición nula, hay que prestar atención al tipo de retorno de la expresión:

Ejemplo

Person person = new Person { Name = Zhang San };

// Para tipos de valor, devuelve Nullable<T>
int? nameLength = person?.Name?.Length;  // El tipo es int?

// Para tipos de referencia, devuelve el tipo en sí.
string name = person?.Name;  // El tipo es string

2. Evitar el uso excesivo

Aunque el operador de condición nula es muy conveniente, no se debe abusar de él:

Ejemplo

// No recomendado - uso excesivo, difícil de entender
var result = obj1?.Property1?.Method1()?.Property2 ?? defaultValue;

// Recomendado - descomposición adecuada, mejora la legibilidad
var temp1 = obj1?.Property1;
var temp2 = temp1?.Method1();
var result = temp2?.Property2 ?? defaultValue;

3. Consideraciones de rendimiento

El operador de condición nula es comparable en rendimiento a la comprobación explícitanullde null, pero las llamadas encadenadas crean variables temporales:

Ejemplo

// Estas dos formas tienen un rendimiento equivalente
// Método 1: comprobación tradicional
if (person != null && person.Address != null)
{
    return person.Address.City;
}

// Método 2: operador condicional Null
return person?.Address?.City;

4. Combinación con invocación de eventos

El operador de condición nula es especialmente adecuado para invocar eventos:

Ejemplo

// Método tradicional
public event EventHandler SomethingHappened;

protected virtual void OnSomethingHappened()
{
    if (SomethingHappened != null)
    {
        SomethingHappened(this, EventArgs.Empty);
    }
}

// Usar el operador condicional null - más conciso
protected virtual void OnSomethingHappened()
{
    SomethingHappened?.Invoke(this, EventArgs.Empty);
}

Ejercicios prácticos

Ejercicio 1: Refactorizar código

Refactoriza el siguientenullcódigo tradicional de comprobación de null para usar el operador de condición nula:

Ejemplo

// Código original
public string GetUserEmail(User user)
{
    if (user != null)
    {
        if (user.Profile != null)
        {
            if (user.Profile.ContactInfo != null)
            {
                return user.Profile.ContactInfo.Email;
            }
        }
    }
    return "Sin información de correo electrónico";
}

// Tu código refactorizado
public string GetUserEmail(User user)
{
    return user?.Profile?.ContactInfo?.Email ?? "Sin información de correo electrónico";
}

Ejercicio 2: Procesar datos de colecciones

Ejemplo

public class Order
{
    public List<OrderItem> Items { get; set; }
    public Customer Customer { get; set; }
}

public class OrderItem
{
    public Product Product { get; set; }
    public int Quantity { get; set; }
}

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class Customer
{
    public string Name { get; set; }
}

// Escribe un método para obtener de forma segura el nombre del primer producto en el pedido
public string GetFirstProductName(Order order)
{
    return order?.Items?.FirstOrDefault()?.Product?.Name ?? "Sin información del producto";
}

Ejercicio 3: Aplicación integral

Ejemplo

// Crea un ejemplo completo que demuestre la aplicación del operador condicional Null en proyectos reales
public class ShoppingCart
{
    public List<CartItem> Items { get; set; }
    public decimal? CalculateTotal()
    {
        return Items?.Sum(item => item?.Product?.Price * item?.Quantity) ?? 0;
    }
}

public class CartItem
{
    public Product Product { get; set; }
    public int? Quantity { get; set; }
}

C# 判断Toma de decisiones en C#

Otras extensiones