Read the syntax
A property exposes get and optional set accessors. Auto-properties store values automatically; a full accessor can validate a new value through the contextual value variable.
A getter-only property can be assigned by its constructor, while an expression-bodied getter computes a result. init permits setting a value during initialization but not by later ordinary assignment.
Syntax
public Type PropertyName { get; set; }Examples
Auto-Implemented Properties
The concise shorthand for simple properties with no custom logic.
Person p = new Person();
p.Name = "John";
p.Age = 21;
Console.WriteLine($"{p.Name} is {p.Age}");
public class Person
{
public string Name { get; set; } = "";
public int Age { get; set; }
}- The concise shorthand for simple properties with no custom logic.
- A property exposes get and optional set accessors. Auto-properties store values automatically; a full accessor can validate a new value through the contextual value variable.
- The auto-properties accept John and 21 after constructing Person. Reading them in the interpolation prints John is 21.
Properties with Validation Logic
A full property with a backing field, letting the setter validate incoming values.
Product item = new Product();
item.Price = 25;
Console.WriteLine(item.Price); // 25
try
{
item.Price = -10; // throws
}
catch (ArgumentException e)
{
Console.WriteLine(e.Message);
}
public class Product
{
private double _price;
public double Price
{
get => _price;
set
{
if (value < 0)
throw new ArgumentException("Price cannot be negative");
_price = value;
}
}
}- A full property with a backing field, letting the setter validate incoming values.
- A property exposes get and optional set accessors. Auto-properties store values automatically; a full accessor can validate a new value through the contextual value variable.
- Setting Price to 25 stores it in _price and prints 25. The negative assignment throws ArgumentException; catch prints the message instead of ending the program.
Read-Only and Computed Properties
A property with only a getter is effectively read-only from outside the class.
Circle c = new Circle(5);
Console.WriteLine(c.Area); // 78.5398...
// c.Radius = 10; // Error - no setter available
public class Circle
{
public double Radius { get; } // set only in the constructor
public Circle(double radius)
{
Radius = radius;
}
public double Area => Math.PI * Radius * Radius; // computed, expression-bodied
}- A property with only a getter is effectively read-only from outside the class.
- A property exposes get and optional set accessors. Auto-properties store values automatically; a full accessor can validate a new value through the contextual value variable.
- The constructor sets Radius to 5; Area calculates Math.PI times radius squared when read. The commented assignment would fail because Radius has no public setter.
init-only Properties
init lets a property be set during object creation (including with object initializers) but not modified afterward.
Order order = new Order { Id = "ORD-1", Total = 49.99 };
Console.WriteLine($"{order.Id}: {order.Total}");
// order.Total = 100; // Error - init-only, can't change after creation
public class Order
{
public string Id { get; init; } = "";
public double Total { get; init; }
}- init lets a property be set during object creation (including with object initializers) but not modified afterward.
- A property exposes get and optional set accessors. Auto-properties store values automatically; a full accessor can validate a new value through the contextual value variable.
- The initializer assigns Id and Total during construction. The later commented mutation would be a compile-time error because Total is init-only.
Best practices
- Use auto-implemented properties ({ get; set; }) by default, and switch to a full property with a backing field only when you need validation or computed logic
- Use { get; } (or init) instead of { get; set; } for values that should never change after an object is created
- Prefer properties over public fields for anything exposed outside the class - it keeps the door open to add logic later without breaking existing callers
- Use expression-bodied properties (=> expression) for simple computed values to keep the class concise
Runtime & versions
.NET runtime. Feature availability depends on the language and runtime version used by your project; consult the official reference below.
C# language reference