C# Tipos anulables (Nullable)
En C#,int、float、bool、DateTimeetc. sontipos de valor, por defecto deben tener un valor y no pueden sernull:
int a = null; // 编译错误:无法将 null 转换为 int
Los tipos anulables (Nullable Types)resuelven este problema: permiten que los tipos de valor tengan un estado adicional de "sin valor" (es decir,null), lo que es muy útil en escenarios donde los datos pueden faltar, como campos de base de datos, valores de retorno de API, etc.
La forma de declararlo es muy sencilla: agrega un?:
int? a = null; // 合法 int? b = 42; // 合法
El de aquíint?SíNullable<int>es azúcar sintáctico (forma abreviada), ambos son completamente equivalentes:
Nullable<int> a = null; // 完整写法 int? a = null; // 简写,效果相同
La siguiente figura muestra cómo funcionan los tipos anulables en memoria: utiliza un marcador booleano adicional para registrar "si tiene valor":
Diferencia entre el signo de interrogación simple ? y el doble ??
En C#, los dos operadores relacionados con los tipos anulables se usan a menudo juntos, pero sus significados son completamente diferentes:
| Operador | Nombre | Uso | Ejemplo |
|---|---|---|---|
? |
Modificador de tipo anulable | Permite que un tipo de valor pueda sernull |
int? i = 3;Equivalente aNullable<int> i = new Nullable<int>(3); |
?? |
Operador de fusión nula (Null-Coalescing Operator) | Cuando la variable esnullproporciona un valor predeterminado |
int result = i ?? 0; |
Una comparación sencilla:
int i; // 普通值类型,默认值为 0,永远不能是 null int? ii; // 可空类型,默认值为 null
Declaración y asignación de tipos anulables
Sintaxis de declaración
<data_type>? <variable_name> = null;
Por ejemplo:
int? age = null; double? temperature = 36.6; bool? isActive = new bool?(); // 显式构造,默认为 null DateTime? birthday = null;
Nullable<T>Puede representar el rango normal de su tipo de valor subyacente, más unnullvalor. Por ejemploNullable<int>puede ser-2,147,483,648llegar2,147,483,647cualquier entero entre ..., onull。
Ejemplo completo
Ejemplo
namespace NullableDemo
{
class Program
{
static void Main(string[] args)
{
// Declarar variables anulables de diferentes tipos
int? num1 = null;
int? num2 = 45;
double? num3 = new double?(); // null
double? num4 = 3.14157;
bool? boolVal = new bool?(); // null
// Mostrar el valor (null se mostrará como cadena vacía)
Console.WriteLine($"num1 = {num1 ?? 0}"); // 0
Console.WriteLine($"num2 = {num2 ?? 0}"); // 45
Console.WriteLine($"num3 = {num3 ?? 0.0}"); // 0
Console.WriteLine($"num4 = {num4 ?? 0.0}"); // 3.14157
Console.WriteLine($"boolVal = {boolVal}"); // (vacío)
}
}
}
Resultado de salida:
num1 = 0 num2 = 45 num3 = 0 num4 = 3.14157 boolVal =
Operador de fusión nula (??)
??El operador se usa para proporcionar a los tipos anulables o tipos de referencia unvalor predeterminado de respaldo. Cuando el lado izquierdo no esnulldevuelve el valor del lado izquierdo; de lo contrario, devuelve el valor del lado derecho:
<表达式1> ?? <表达式2>
- Si
<表达式1>no esnull, devuelve<表达式1>; - de lo contrario, devuelve
<表达式2>。
Desde C# 8.0, también se puede usar??=(operador de asignación de fusión nula), solo cuando la variable esnullse realiza la asignación:
int? x = null; x ??= 10; // x 为 null,赋值为 10 x ??= 20; // x 已有值 10,不再赋值
Ejemplo
namespace NullableDemo
{
class Program
{
static void Main(string[] args)
{
double? num1 = null;
double? num2 = 3.14157;
// ?? proporciona el valor predeterminado
double result1 = num1 ?? 5.34; // num1 es null → devuelve 5.34
double result2 = num2 ?? 5.34; // num2 tiene valor → devuelve 3.14157
Console.WriteLine($"num1 ?? 5.34 = {result1}"); // 5.34
Console.WriteLine($"num2 ?? 5.34 = {result2}"); // 3.14157
// Uso en cadena: proporcionar múltiples valores alternativos
int? a = null;
int? b = null;
int? c = 42;
int value = a ?? b ?? c ?? 0; // Se intenta uno por uno, finalmente se obtiene 42
Console.WriteLine($"a ?? b ?? c ?? 0 = {value}"); // 42
}
}
}
Resultado de salida:
num1 ?? 5.34 = 5.34 num2 ?? 5.34 = 3.14157 a ?? b ?? c ?? 0 = 42
Propiedades y métodos comunes de los tipos anulables
| Miembro | Descripción | Ejemplo |
|---|---|---|
.HasValue |
Determina si la variable tiene valor (devuelvebool) |
if (num.HasValue) { ... } |
.Value |
Obtiene el valor real (si esnulllanzaInvalidOperationException) |
int x = num.Value; |
.GetValueOrDefault() |
Obtiene el valor de forma segura, si esnulldevuelve el valor predeterminado del tipo (como0) |
num.GetValueOrDefault() |
.GetValueOrDefault(T) |
Obtiene el valor de forma segura, si esnulldevuelve el valor predeterminado especificado |
num.GetValueOrDefault(100) |
?? |
Operador de fusión nula (azúcar sintáctico, equivalente aGetValueOrDefault) |
int result = num ?? 100; |
Ejemplo
namespace NullableDemo
{
class Program
{
static void Main(string[] args)
{
int? num = null;
// HasValue + Value (método tradicional)
if (num.HasValue)
Console.WriteLine($"Valor: {num.Value}");
else
Console.WriteLine("num no tiene valor");
// Obtener el valor predeterminado de forma segura
Console.WriteLine(num.GetValueOrDefault()); // 0
Console.WriteLine(num.GetValueOrDefault(99)); // 99
Console.WriteLine(num ?? 99); // 99 (forma equivalente)
// ⚠ Nota: acceder directamente a .Value lanzará una excepción
// int x = num.Value; // InvalidOperationException!
}
}
}
Escenarios de aplicación práctica
Los tipos anulables son muy comunes en el desarrollo real, especialmente al manejar datos que pueden faltar:
Mapeo de campos de base de datos
Los campos de la base de datos pueden serNULL, con los tipos anulables se puede hacer una correspondencia precisa:
| ID de usuario | Edad | Activo |
|---|---|---|
| 1 | 28 | true |
| 2 | null | false |
int? age = GetUserAgeFromDB(userId: 2);
// 安全处理 null
string display = age.HasValue
? $"用户年龄:{age.Value}"
: "年龄未知";
// 或者更简洁的写法
string display2 = $"用户年龄:{age ?? 0}";
Parámetros opcionales y configuración
// 配置项可能未设置
int? timeout = GetConfigValue("timeout");
int actualTimeout = timeout ?? 30; // 未设置时使用默认值 30 秒
Comprobación de nulos en cadena (C# 6.0+)
// 使用 ?. 运算符安全访问可能为 null 的对象 string? name = user?.Address?.City?.Name; // 如果 user、Address、City 中任何一个为 null,结果就是 null,不会抛异常
Resumen
| Función | Ejemplo | Descripción |
|---|---|---|
| Definir tipo anulable | int? x = null; |
Equivalente aNullable<int> |
| Determinar si tiene valor | x.HasValue |
Devuelvetrueofalse |
| Obtener el valor (no seguro) | x.Value |
Si esnulllanzaInvalidOperationException |
| Obtener el valor predeterminado | x ?? 0 |
Si esnulldevuelve el valor del lado derecho |
| Obtener el valor predeterminado especificado | x.GetValueOrDefault(10) |
Si esnulldevuelve 10 |
| Asignación de fusión nula | x ??= 10 |
Solo cuandoxParanullse asigna el valor (C# 8.0+) |
| Acceso de navegación segura | user?.Name |
siuserParanullentonces devuelvenull(C# 6.0+) |
Los "tipos de referencia anulables" de C# 8.0
Desde C# 8.0, se introdujeron lostipos de referencia anulables (Nullable Reference Types), que junto con lostipos de valor anulablesson dos mecanismos diferentes:
| Elemento de comparación | Tipos de valor anulables | Tipos de referencia anulables |
|---|---|---|
| Ejemplo | int? |
string? |
| Aplica a | Tipos de valor (int、bool、structetc.) |
Tipos de referencia (string、class, arreglos, etc.) |
| Implementación | En tiempo de ejecución, medianteNullable<T>implementación con struct |
El compilador realiza análisis estático, no cambia el comportamiento en tiempo de ejecución. |
| Estado predeterminado | Siempre presente (desde C# 1.0) | Debe habilitarse en el proyecto<Nullable>enable</Nullable> |
| comprobación de null | usar.HasValueDeterminar |
El compilador emite advertencias (no errores) |
Otras extensionesLos tipos de referencia anulables son una herramienta de verificación de seguridad en tiempo de compilación: no cambian el comportamiento en tiempo de ejecución del programa, pero en los lugares donde el código podría producir
NullReferenceExceptionemitirá advertencias del compilador, ayudándote a detectar problemas potenciales en la etapa de desarrollo.