Campos de respaldo
Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy — lección 17 de 70.
Las propiedades autoimplementadas son convenientes, pero a veces se necesita más control sobre cómo una propiedad almacena o recupera su valor. Ahí es donde entran los campos de respaldo (backing fields). Un campo de respaldo es un campo privado que almacena los datos reales de una propiedad.
public class Product
{
private decimal _price; // Campo de respaldo
public decimal Price
{
get { return _price; }
set { _price = value; }
}
}Esto parece un trabajo extra en comparación con las auto-propiedades, pero los campos de respaldo permiten añadir lógica. Por ejemplo, puedes validar los datos antes de almacenarlos:
public class Product
{
private decimal _price;
public decimal Price
{
get => _price;
set => _price = value < 0 ? 0 : value;
}
}Ahora los precios negativos se convierten automáticamente en cero. También puedes transformar datos al leer o escribir, registrar cambios o activar otras acciones.
La convención de nomenclatura para el campo de respaldo (backing field) normalmente utiliza un prefijo de guion bajo (_price) o minúsculas (price) para distinguirlo de la propiedad.
Cuando usas propiedades autoimplementadas como public decimal Price { get; set; }, el compilador crea en realidad un campo de respaldo oculto para ti. Los campos de respaldo explícitos te brindan el mismo almacenamiento con un control total sobre el comportamiento.
Desafío
FácilVamos a construir un sistema de sensor de temperatura que utiliza campos de respaldo (backing fields) para validar y transformar datos a medida que se almacenan y recuperan.
Crearás dos archivos para organizar tu código:
TemperatureSensor.cs: Define una claseTemperatureSensoren el espacio de nombresSensors. Este sensor mide la temperatura en grados Celsius, pero debemos asegurarnos de que las lecturas se mantengan dentro de límites válidos. Utiliza campos de respaldo para implementar lo siguiente:- Una propiedad
Location(string) con un campo de respaldo_location. Al establecer la ubicación, si el valor es nulo o está vacío, almacena"Unknown"en su lugar. - Una propiedad
Temperature(double) con un campo de respaldo_temperature. Al establecer la temperatura, limita el valor entre-50y150(si es inferior a -50, almacena -50; si es superior a 150, almacena 150). - Una propiedad de solo lectura
TemperatureFahrenheitque calcula y devuelve la temperatura en Fahrenheit utilizando la fórmula:(celsius * 9 / 5) + 32. Esta debe utilizar el campo de respaldo directamente. - Un constructor que acepte los valores de ubicación y temperatura inicial.
- Una propiedad
Program.cs: En tu archivo principal, crea un sensor utilizando los valores de entrada y muestra sus lecturas. Luego, actualiza la temperatura con un segundo valor de entrada y muestra las lecturas actualizadas.
Recibirás tres entradas:
- Ubicación del sensor
- Lectura de temperatura inicial
- Lectura de temperatura actualizada
Imprime la salida en este formato:
Sensor: {Location}
Temperature: {Temperature}C ({TemperatureFahrenheit}F)
Updated Temperature: {Temperature}C ({TemperatureFahrenheit}F)Por ejemplo, si las entradas son Lab Room, 25, y 200, la salida debería ser:
Sensor: Lab Room
Temperature: 25C (77F)
Updated Temperature: 150C (302F)Observa cómo la segunda lectura de 200 se limita a 150 porque excede la temperatura máxima válida. ¡Tus campos de respaldo te dan este control sobre cómo se almacenan los datos!
Hoja de referencia
Un campo de respaldo (backing field) es un campo privado que almacena los datos reales de una propiedad, lo que permite agregar lógica personalizada para obtener y establecer valores.
Sintaxis básica de un campo de respaldo
public class Product
{
private decimal _price; // Campo de respaldo
public decimal Price
{
get { return _price; }
set { _price = value; }
}
}Sintaxis de cuerpo de expresión
public decimal Price
{
get => _price;
set => _price = value;
}Agregar lógica de validación
Los campos de respaldo permiten validar o transformar datos antes de almacenarlos:
private decimal _price;
public decimal Price
{
get => _price;
set => _price = value < 0 ? 0 : value; // Evitar precios negativos
}Convención de nomenclatura
Los campos de respaldo suelen utilizar un prefijo de guion bajo (_price) o minúsculas (price) para distinguirlos del nombre de la propiedad.
Autopropiedades frente a campos de respaldo
Las propiedades implementadas automáticamente como public decimal Price { get; set; } crean automáticamente un campo de respaldo oculto. Los campos de respaldo explícitos proporcionan el mismo almacenamiento con un control total sobre el comportamiento.
Pruébalo tú mismo
using System;
using Sensors;
class Program
{
public static void Main(string[] args)
{
// Leer entradas
string location = Console.ReadLine();
double initialTemp = Convert.ToDouble(Console.ReadLine());
double updatedTemp = Convert.ToDouble(Console.ReadLine());
// TODO: Crear un TemperatureSensor con la ubicación y la temperatura inicial
// TODO: Imprimir la ubicación del sensor y las lecturas de temperatura inicial
// Formato: "Sensor: {Location}"
// Formato: "Temperature: {Temperature}C ({TemperatureFahrenheit}F)"
// TODO: Actualizar la temperatura del sensor con el valor actualizado
// TODO: Imprimir las lecturas de temperatura actualizadas
// Formato: "Updated Temperature: {Temperature}C ({TemperatureFahrenheit}F)"
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosNamespaces y directivasIntro a clases y objetosLa palabra clave 'this'Métodos y parámetrosCampos vs PropiedadesConstructoresInicializadores de objetosResumen - Calculadora simple4Herencia
Sintaxis básica de herencia (:)La palabra clave 'base'Palabras clave Virtual y OverrideClases selladas (Sealed)La clase base 'object'Resumen: Jerarquía de empleados7Características avanzadas
Sobrecarga de operadoresIndexadores (this[])Sobrescritura de ToString()Métodos de extensiónResumen - Lista personalizada10Patrones de diseño - Parte 1
Introducción a los patrones de diseñoSingleton Thread-SafePatrón FactoryPatrón Observer (Eventos)Patrón Strategy2Propiedades y miembros estáticos
Propiedades autoimplementadasPropiedades de solo lectura y escrituraCampos y métodos estáticosClases estáticasMiembros con cuerpo de expresión5Polimorfismo e Interfaces
Polimorfismo: Compilación vs. EjecuciónInterfaz vs. Clase AbstractaInterfaces MúltiplesInterfaces ExplícitasUpcasting y DowncastingRepaso: Calculadora de Figuras8Conceptos avanzados de POO
Composición sobre herenciaGenéricos (clases y métodos)Delegados y eventosAtributos y ReflexiónIDisposable y la sentencia usingFundamentos de Inyección de dependencias11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Arquitectura de clases
Datos de instancia vs. estáticosPalabras clave 'readonly' y 'const'Campos de respaldoResumen - Gestor de cuentas bancarias6Encapsulamiento
Modificadores de accesoPropiedades para el encapsulamientoImplementación de ocultamiento de datosPatrones de inmutabilidadRepaso - Registros de estudiantes