Backing Fields
Part of the Object Oriented Programming section of Coddy's C# journey — lesson 17 of 70.
Auto-implemented properties are convenient, but sometimes you need more control over how a property stores or retrieves its value. That's where backing fields come in. A backing field is a private field that stores the actual data for a property.
public class Product
{
private decimal _price; // Backing field
public decimal Price
{
get { return _price; }
set { _price = value; }
}
}This looks like extra work compared to auto-properties, but backing fields let you add logic. For example, you can validate data before storing it:
public class Product
{
private decimal _price;
public decimal Price
{
get => _price;
set => _price = value < 0 ? 0 : value;
}
}Now negative prices automatically become zero. You can also transform data when reading or writing, log changes, or trigger other actions.
The backing field naming convention typically uses an underscore prefix (_price) or lowercase (price) to distinguish it from the property.
When you use auto-implemented properties like public decimal Price { get; set; }, the compiler actually creates a hidden backing field for you. Explicit backing fields give you the same storage with full control over the behavior.
Challenge
EasyLet's build a temperature sensor system that uses backing fields to validate and transform data as it's stored and retrieved.
You'll create two files to organize your code:
TemperatureSensor.cs: Define aTemperatureSensorclass in theSensorsnamespace. This sensor measures temperature in Celsius, but we need to ensure the readings stay within valid bounds. Use backing fields to implement the following:- A
Locationproperty (string) with a backing field_location. When setting the location, if the value is null or empty, store"Unknown"instead. - A
Temperatureproperty (double) with a backing field_temperature. When setting the temperature, clamp the value between-50and150(if below -50, store -50; if above 150, store 150). - A read-only property
TemperatureFahrenheitthat calculates and returns the temperature in Fahrenheit using the formula:(celsius * 9 / 5) + 32. This should use the backing field directly. - A constructor that accepts location and initial temperature values.
- A
Program.cs: In your main file, create a sensor using input values and display its readings. Then update the temperature with a second input value and show the updated readings.
You will receive three inputs:
- Sensor location
- Initial temperature reading
- Updated temperature reading
Print the output in this format:
Sensor: {Location}
Temperature: {Temperature}C ({TemperatureFahrenheit}F)
Updated Temperature: {Temperature}C ({TemperatureFahrenheit}F)For example, if the inputs are Lab Room, 25, and 200, the output should be:
Sensor: Lab Room
Temperature: 25C (77F)
Updated Temperature: 150C (302F)Notice how the second reading of 200 gets clamped to 150 because it exceeds the maximum valid temperature. Your backing fields give you this control over how data is stored!
Cheat sheet
A backing field is a private field that stores the actual data for a property, allowing you to add custom logic for getting and setting values.
Basic Backing Field Syntax
public class Product
{
private decimal _price; // Backing field
public decimal Price
{
get { return _price; }
set { _price = value; }
}
}Expression-Bodied Syntax
public decimal Price
{
get => _price;
set => _price = value;
}Adding Validation Logic
Backing fields allow you to validate or transform data before storing it:
private decimal _price;
public decimal Price
{
get => _price;
set => _price = value < 0 ? 0 : value; // Prevent negative prices
}Naming Convention
Backing fields typically use an underscore prefix (_price) or lowercase (price) to distinguish them from the property name.
Auto-Properties vs Backing Fields
Auto-implemented properties like public decimal Price { get; set; } automatically create a hidden backing field. Explicit backing fields give you the same storage with full control over the behavior.
Try it yourself
using System;
using Sensors;
class Program
{
public static void Main(string[] args)
{
// Read inputs
string location = Console.ReadLine();
double initialTemp = Convert.ToDouble(Console.ReadLine());
double updatedTemp = Convert.ToDouble(Console.ReadLine());
// TODO: Create a TemperatureSensor with the location and initial temperature
// TODO: Print the sensor location and initial temperature readings
// Format: "Sensor: {Location}"
// Format: "Temperature: {Temperature}C ({TemperatureFahrenheit}F)"
// TODO: Update the sensor's temperature with the updated value
// TODO: Print the updated temperature readings
// Format: "Updated Temperature: {Temperature}C ({TemperatureFahrenheit}F)"
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesNamespaces & DirectivesIntro to Classes & ObjectsThe 'this' KeywordMethods and ParametersFields vs PropertiesConstructorsObject InitializersRecap - Simple Calculator4Inheritance
Basic Inheritance (:) SyntaxThe 'base' KeywordVirtual & Override KeywordsSealed ClassesThe 'object' Base ClassRecap - Employee Hierarchy7Advanced Features
Operator OverloadingIndexers (this[])ToString() OverrideExtension MethodsRecap - Custom List2Properties & Static Members
Auto-Implemented PropertiesRead/Write-Only PropertiesStatic Fields & MethodsStatic ClassesExpression-Bodied Members5Polymorphism & Interfaces
Compile vs Runtime PolyInterface vs Abstract ClassMultiple InterfacesExplicit InterfacesUpcasting & DowncastingRecap - Shape Calculator