Public fields work, but they're dangerous. Anyone can set myCar.year = -5; and your object is in a bad state. Properties give you the control of methods with the convenience of fields.
Properties with get/set
A property looks like a field but has get and set blocks. The get block runs when you read the value, and set runs when you assign to it.
class Car
{
private int year;
public int Year
{
get { return year; }
set
{
if (value >= 1886)
year = value;
}
}
}
Car myCar = new Car();
myCar.Year = 2023;
Console.WriteLine(myCar.Year);
myCar.Year = -5;
Console.WriteLine(myCar.Year);
value is a keyword that holds whatever is assigned to the property. Here we reject years before 1886 (the first car was invented that year).
Auto-Implemented Properties
Most properties just store and return a value with no extra logic. C# gives you a shortcut: auto-implemented properties. You don't need a backing field โ the compiler creates one for you.
class Car
{
public string Brand { get; set; }
public int Year { get; set; }
}
Car myCar = new Car();
myCar.Brand = "Ford";
myCar.Year = 2022;
Console.WriteLine($"{myCar.Brand} ({myCar.Year})");
Clean and simple. Use a regular property when you need logic, auto-properties when you don't.
Read-Only and Write-Only Properties
Remove set and you get a read-only property. Remove get and it's write-only. Read-only is common โ good for computed values or values set only in the constructor.
class Car
{
public string Brand { get; }
public Car(string brand)
{
Brand = brand;
}
}
Car myCar = new Car("Tesla");
Console.WriteLine(myCar.Brand);
Once the constructor sets Brand, nobody can change it. That's a great way to make your objects safer.
Why Properties Over Public Fields?
Three big reasons: validation (reject bad values), computed values (a FullName property that combines FirstName and LastName), and future-proofing. If you start with a public field and later need logic, you break every piece of code that uses it. With properties, you can add logic without changing the public interface.