Cuando trabajamos con genéricos en C#, nos enfrentamos a una pregunta clave:
¿cómo inicializo un valor de un tipo que aún no conozco?
Para esto existe la palabra clave default, que nos permite obtener el valor por defecto de cualquier tipo, sea valor o referencia.
En C#, cada tipo tiene un valor por defecto:
- Tipos por referencia (class, string, object) → null.
- Tipos numéricos (int, double, etc.) → 0.
- bool → false.
- Estructuras (struct) → todos sus campos inicializados a 0 o null.
Ejemplo:
int numero = default; // 0
bool bandera = default; // false
string texto = default; // null
En un método genérico no sabemos de antemano si T es un tipo de referencia o de valor.
default(T) resuelve este problema devolviendo el valor inicial correcto según el tipo.
public T ObtenerPrimerElemento<T>(List<T> lista)
{
if (lista.Count > 0)
return lista[0];
else
return default(T); // null si T es referencia, 0/false/etc si es valor
}
Ejemplo de uso:
Console.WriteLine(ObtenerPrimerElemento(new List<int>())); // 0
Console.WriteLine(ObtenerPrimerElemento(new List<string>())); // null
A partir de C# 7.1, se introdujo una sintaxis más corta: simplemente default sin necesidad de escribir el tipo entre paréntesis.
T valor = default; // equivalente a default(T)
Esto simplifica la escritura en genéricos y métodos.
Un ejemplo muy común es al buscar un valor en un diccionario sin estar seguros de que exista:
public TValue Buscar<TKey, TValue>(Dictionary<TKey, TValue> dic, TKey clave)
{
if (dic.TryGetValue(clave, out TValue valor))
return valor;
return default; // null si TValue es referencia, 0/false si es valor
}
La palabra clave default es una herramienta poderosa para manejar genéricos en C#.
Permite escribir código seguro y flexible sin preocuparnos si T es una clase o un struct, y desde C# 7.1 la sintaxis se volvió aún más simple y expresiva.