Un constructor es un método especial que se ejecuta automáticamente en el momento en que creamos una instancia de una clase (cuando usamos new).
Su misión principal es inicializar el estado del objeto para que sea válido desde el principio de su existencia.
Sintaxis Básica
Un constructor tiene dos características que lo hacen único:
- Tiene el mismo nombre que la clase.
- No tiene tipo de retorno (ni siquiera
void).
Por ejemplo, para la clase Usuario.
public class Usuario
{
public string Nombre { get; set; }
// Este es el Constructor
public Usuario()
{
Nombre = "Sin Nombre"; // Inicialización por defecto
Console.WriteLine("¡Ha nacido un usuario!");
}
}
// Al hacer 'new', el código del constructor se ejecuta
Usuario user = new Usuario();
Cuando hacemos new Usuario(), lo que ocurre en la memoria (Heap) es
- Primero se reserva el espacio para el objeto
- Inmediatamente después, se llama al constructor.
El constructor por defecto
Si no escribes ningún constructor, C# genera uno invisible por ti: el Constructor por Defecto (sin parámetros). Este no hace nada más que inicializar las variables a sus valores predeterminados (0, null, false).
Pero en cuanto escribes tú un constructor con parámetros, el constructor por defecto desaparece (C# solo lo genera si no hay otro constructor).
public class Producto
{
public string Nombre { get; set; }
public Producto(string nombre) // Constructor propio
{
Nombre = nombre;
}
}
// ESTO DARÁ ERROR DE COMPILACIÓN
Producto p = new Producto();
El compilador te dirá: “¿Perdona? Me has dicho que para crear un producto necesito un nombre. No puedes crearlo vacío.”
Si queréis tener ambos (uno vacío y uno con parámetros), debéis escribir explícitamente el constructor vacío.
Sobrecarga de constructores
Al igual que con cualquier otro método, podemos tener múltiples constructores con diferentes firmas (parámetros). Esto permite crear objetos de diferentes formas.
public class Rectangulo
{
public int Ancho { get; set; }
public int Alto { get; set; }
// Opción 1: Sin nada (todo a 0)
public Rectangulo() { }
// Opción 2: Un cuadrado (ancho = alto)
public Rectangulo(int lado)
{
Ancho = lado;
Alto = lado;
}
// Opción 3: Un rectángulo específico
public Rectangulo(int ancho, int alto)
{
Ancho = ancho;
Alto = alto;
}
}
Aquí tenemos distintos constructores válidos para Rectangulo
Encadenamiento de constructores
Podemos hacer que un constructor llame a otro usando la palabra clave this. De esta forma, centralizamos la lógica de inicialización en un único punto.
public class Robot
{
public string Nombre { get; set; }
public int Bateria { get; set; }
// Constructor base que hace el trabajo real
public Robot(string nombre, int bateria)
{
Nombre = nombre;
Bateria = bateria;
}
// Llama al constructor base usando 'this'
public Robot(string nombre) : this(nombre, 100)
{
// Aquí solo código adicional si fuera necesario
}
}
Cuando llamamos a new Robot("R2D2"), primero se ejecuta el constructor de dos parámetros (poniendo batería a 100) y luego vuelve al de un parámetro.
Inicializadores de Objetos
Desde C# 3.0, tenemos una sintaxis maravillosa para establecer propiedades públicas justo después de crear el objeto, sin necesidad de crear cientos de constructores.
// Sin constructor específico, usando Inicializador
Personaje p = new Personaje
{
Nombre = "Mario",
Nivel = 1,
Vida = 100
};
Esto es equivalente a crear el objeto vacío y luego asignar las propiedades una a una, pero mucho más legible y atómico.
Diferencia Clave:
- El Constructor se usa para asegurar dependencias OBLIGATORIAS (invariantes).
- El Inicializador se usa para configurar propiedades OPCIONALES.
Constructores estáticos
A veces necesitamos inicializar cosas que no pertenecen a una instancia concreta, sino a la clase en general (variables static). Para eso existe el constructor estático.
- No tiene modificador de acceso (no es public ni private).
- No tiene parámetros.
- Se ejecuta una sola vez: automáticamente antes de que se cree la primera instancia o se acceda a cualquier miembro estático.
public class Servidor
{
public static DateTime HoraInicio;
// Se ejecuta una sola vez en toda la vida de la aplicación
static Servidor()
{
HoraInicio = DateTime.Now;
Console.WriteLine("Servidor inicializado.");
}
}
No es algo muy habitual. En general no queréis hacer esto (salvo que sepaís exáctamente porqué necesitáis hacerlo así)
Primary constructors
C# 12 introdujo los Constructores Primarios para clases normales (antes solo existían en records). Esto nos permite reducir drásticamente el código repetitivo (“boilerplate”).
En lugar de definir el constructor dentro, ponemos los parámetros directamente en la definición de la clase.
public class Servicio
{
private ILogger _logger;
public Servicio(ILogger logger)
{
_logger = logger;
}
}
// Los parámetros van arriba, junto al nombre de la clase
public class Servicio(ILogger logger)
{
public void Log(string mensaje)
{
// Podemos usar 'logger' directamente en toda la clase
logger.Log(mensaje);
}
}
Es mucho más limpio, C# se encarga de gestionar esos parámetros para que estén disponibles en toda la clase.
