Codectionary / Developer documentation / C#

Properties (get/set)

Properties are C#'s idiomatic way to expose class data through accessor-like syntax while still allowing controlled access via get and set. Unlike a plain public field, a property can validate a value before it's set, compute a value on the fly, or restrict access to read-only. Auto-implemented properties (using { get; set; } with no body) provide a concise shorthand when no custom logic is needed.

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; }
}
  1. The concise shorthand for simple properties with no custom logic.
  2. 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.
  3. 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;
        }
    }
}
  1. A full property with a backing field, letting the setter validate incoming values.
  2. 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.
  3. 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
}
  1. A property with only a getter is effectively read-only from outside the class.
  2. 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.
  3. 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; }
}
  1. init lets a property be set during object creation (including with object initializers) but not modified afterward.
  2. 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.
  3. 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

Specifications & further reading