Operador de condición nula 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
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
{
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
{
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
{
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? 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
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
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
string displayName = person?.Name ?? (person != null ? Usuario anónimo : el usuario no existe);
3. Uso en consultas LINQ
Ejemplo
{
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
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 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 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
// 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
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
// 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
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
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 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
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; }
}
Sentencias de decisión en C#