Seguridad nula de C#

Tip

Este artículo forma parte de la sección Aspectos básicos de los desarrolladores que ya 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 .

¿Viene de Java o C++? C# proporciona seguridad nula en tiempo de compilación a través de tipos de referencia que aceptan valores NULL. El objetivo es similar a las anotaciones de Java @NonNull, pero aplicadas por el compilador. C# también tiene operadores dedicados como ?. y ?? que hacen que las expresiones seguras con valores NULL sean concisas.

null representa la ausencia de un valor. Al intentar acceder a un miembro en una referencia null, ya sea llamando a un método o leyendo una propiedad, el tiempo de ejecución produce un NullReferenceException:

// Accessing a member on null throws NullReferenceException at runtime:
// string? name = null;
// int length = name.Length; // throws NullReferenceException

// Check before you dereference:
string? name = null;
if (name is not null)
{
    Console.WriteLine($"Name has {name.Length} characters.");
}
else
{
    Console.WriteLine("Name has no value.");
}
// Output: Name has no value.

C# proporciona tres herramientas complementarias para escribir código seguro para null:

  • Tipos de valor anulables: permite que un tipo de valor como int o bool también pueda contener null.
  • Tipos de referencia que aceptan valores NULL: permite que el compilador realice un seguimiento de si una referencia podría ser null
  • Operadores nulos: expresan acceso seguro para valores nulos y lógica de reserva concisa

Tipos de valor anulables

Los tipos de valor como int, doubley bool no pueden contener null de forma predeterminada. Agregue ? al nombre del tipo para crear un tipo de valor anulable que pueda contener un valor o null:

int? score = null;
Console.WriteLine(score.HasValue);               // False

score = 95;
Console.WriteLine(score.HasValue);               // True
Console.WriteLine(score.GetValueOrDefault());    // 95

int? missing = null;
Console.WriteLine(missing.GetValueOrDefault(-1)); // -1

Los tipos de valor que aceptan valores NULL son útiles cuando un tipo de valor subyacente debe representar "sin datos". Entre los escenarios comunes se incluyen columnas de base de datos que podrían estar ausentes, opciones de configuración opcionales y lecturas del sensor que aún no se capturan.

Para obtener una cobertura completa de declaración, comprobación y conversión, consulte Tipos de valor anulables.

Tipos de referencia anulables

Los tipos de referencia, como string, matrices y las instancias de clase, pueden contener null en tiempo de ejecución. Los tipos de referencia que aceptan valores NULL son una característica del compilador que hace que la intención null sea explícita y detecta errores en tiempo de compilación.

Mediante la ? anotación, declara la intención:

  • string? : esta referencia puede ser null; el compilador advierte si se desreferencia sin comprobar primero.
  • string : esta referencia no debe ser null; el compilador advierte si lo asigna null .
// string?  means this reference might be null
// string   means this reference should not be null
string? nullableName = null;
string  nonNullName  = "Alice";

// ?. safely accesses a member when the reference might be null
string display = nullableName?.ToUpper() ?? "(no name)";
Console.WriteLine(display);         // (no name)

display = nonNullName.ToUpper();    // safe: nonNullName is never null
Console.WriteLine(display);         // ALICE

Todos los proyectos .NET que las plantillas de SDK modernas crean habilitan los tipos de referencia que aceptan valores NULL de forma predeterminada. Para obtener instrucciones completas sobre cómo habilitar y anotar, consulte Tipos de referencia que aceptan valores NULL.

Operadores NULL

C# incluye varios operadores que permiten escribir código seguro para null sin protección manual if-null en todas partes:

Operador Name propósito
?. El operador "null conditional member access" Obtener acceso a un miembro solo cuando el objeto no es NULL
?[] Acceso a índices condicionales nulos Acceso a un elemento solo cuando la colección no es NULL
?? Uso combinado de Null Devuelve un valor de reserva cuando la expresión es null
??= Asignación de uso combinado de NULL Asignar solo cuando la variable es null
is null / is not null Patrón NULL Prueba null preferida
string? city = GetCity();

// ?. — access a member only when non-null
int? len = city?.Length;

// ?? — substitute a default when null
string display = city ?? "unknown";

// is null — preferred null test
if (city is null)
{
    Console.WriteLine("No city provided.");
}
else
{
    Console.WriteLine($"{display} ({len} chars)");
}
// Output: No city provided.

Para obtener ejemplos detallados de cada operador, consulte Operadores NULL.

Los tipos de valores y tipos de referencia que aceptan valores Null sirven para distintos propósitos

Los tipos de valor que aceptan valores nulos y los tipos de referencia que aceptan valores nulos no son opciones. Resuelven diferentes problemas:

  • Se usa T? para un tipo de valor que necesita representar "sin valor". Por ejemplo, use int? para una columna de base de datos opcional o DateTime? para un evento que aún no esté programado.
  • Use string? y otras anotaciones de referencia que aceptan valores Null para documentar que una referencia podría ser null, de modo que el compilador pueda advertirle antes de que se produzca un error NullReferenceException en tiempo de ejecución.

Juntas, estas características y los operadores NULL proporcionan un conjunto completo de herramientas para escribir código C# seguro para null.