1. Introducción
Vamos a empezar con los problemas que aparecen cuando usas campos directamente. Si declaras un campo como public, cualquiera podrá cambiarlo directamente desde cualquier parte del programa:
public class Dog
{
public string Name;
}
Dog dog = new Dog();
dog.Name = ""; // O_o ... esto es como "nombre del perro = cadena vacía"!
El usuario puede ponerle al campo Name cualquier valor flipante, incluso cosas que no tienen sentido para tu dominio: una cadena vacía, un nombre demasiado largo, o incluso null. Es como si alguien estuviera montando tu nuevo armario de IKEA y tú le dieras acceso total a la fábrica de carpintería.
Recuerda que encapsulación es cuando el objeto controla sus propios datos. No dejamos que cualquiera meta mano en las tripas, sino que damos "puertas" especiales — propiedades (Properties), a través de las cuales se accede al campo, pero con posibilidad de comprobar, registrar, modificar o reaccionar de alguna forma cuando cambian los valores.
2. Definición y sintaxis
Una propiedad es un miembro especial de la clase que parece casi un campo, pero en realidad por debajo es un par de métodos especiales: getter (obtener valor) y setter (asignar valor). Con una propiedad puedes:
- Permitir (o prohibir) leer/escribir datos;
- Añadir validación o lógica al acceder a los datos;
- Ocultar el campo interno e incluso guardar el valor en otro sitio.
La propiedad se declara casi igual que un campo, solo que con llaves y las palabras clave get y set dentro.
[modificador_de_acceso] tipo NombrePropiedad
{
get { ... }
set { ... }
}
Aquí tienes un ejemplo para nuestra clase Dog:
public class Dog
{
private string _name; // campo interno (¡private!)
public string Name
{
get { return _name; } // "getter": obtener nombre
set { _name = value; } // "setter": asignar nombre
}
}
Nota: el guion bajo se suele usar para campos privados (_name). Es el estándar de estilo en C#.
3. Cómo funciona una propiedad
La propiedad es como un "guardián" que está entre los datos internos del objeto y el mundo exterior. Ejemplo:
Dog dog = new Dog();
dog.Name = "Sharik";
Console.WriteLine(dog.Name);
Explicación:
- Cuando el programa llega a la línea dog.Name = "Sharik"; — ahí se llama al método set de la propiedad, y puedes meter cualquier comprobación que quieras (por ejemplo, que el nombre no esté vacío).
- En Console.WriteLine(dog.Name); se llama al método get, que simplemente devuelve el valor actual o, si quieres, algo calculado dinámicamente.
Parece un campo normal, pero en realidad aquí todo está bajo control.
4. Por qué las propiedades son "Best Practice"
Casi nunca damos acceso directo a los campos internos de un objeto. Aunque ahora no parezca necesario comprobar nada, acostumbrarse a envolver los datos en propiedades te salva la vida cuando las reglas cambian.
Ejemplo de "validación" al asignar:
public class Dog
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("¡El nombre del perro no puede estar vacío!");
}
_name = value;
}
}
}
Ahora esto:
dog.Name = ""; // ¡Lanzará una excepción!
… protege nuestro objeto de valores absurdos.
5. Propiedades: solo lectura, solo escritura y normales
A veces solo quieres permitir ver el valor (por ejemplo, el año de nacimiento del perro, que no se puede cambiar), o al revés — solo asignar (raro, pero igual quieres hacer algo misterioso).
- Solo lectura: solo pones get, quitas set.
- Solo escritura: solo pones set, quitas get.
Ejemplos:
public class Dog
{
private int _birthYear = 2018;
// Solo lectura
public int BirthYear
{
get { return _birthYear; }
}
// Solo escritura (muy raro)
public string Secret
{
set { /* hacemos algo con value */ }
}
}
6. Propiedades vs campos
| Campo | Propiedad | |
|---|---|---|
| Sintaxis | |
|
| Acceso | Directo | Por get/set |
| Validación | No | Puedes añadir en set/get |
| Extensibilidad | No | Puedes modificar cuando quieras |
| Integración con IDE | Se ven como campos | Se ven como propiedades (importante para frameworks) |
Ilustración: Cómo funciona una propiedad
sequenceDiagram
participant User as Usuario del objeto
participant Dog as Objeto Dog
participant Field as Campo privado _name
User->>Dog: dog.Name = "Ryzhik"
Dog->>Dog: set Name("Ryzhik")
Dog->>Field: _name = "Ryzhik"
User->>Dog: print(dog.Name)
Dog->>Dog: get Name()
Dog->>Field: lee _name
Dog->>User: devuelve "Ryzhik"
7. Errores típicos y matices
Vamos a ver dónde pueden estar las trampas.
Un error típico es confundir campos y propiedades, y sin querer exponer datos privados:
public string name; // ¡Esto es un campo! ¡Se ve en todas partes, peligroso!
Mejor así:
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
Propiedades estáticas existen para guardar valores comunes a todos los objetos. Pero úsalas con cuidado.
Curioso: si una propiedad solo tiene get y ningún constructor, no se puede cambiar nunca — eso se llama immutable property y se usa mucho en los enfoques modernos de diseño (volveremos a esto en las lecciones sobre record e inmutabilidad de datos).
GO TO FULL VERSION