# Auto-Properties and Read-Only Properties

Write short auto-properties, make a property read-only to the outside with private set or get-only, and calculate a property from others.

Apprentice · C# · OOP · Updated November 3, 2026

## After this lesson you can

- Write auto-properties, including ones that only the class can set
- Write a calculated property that works out its value from other properties

## Key takeaways

- `{ get; set; }` is an auto-property: C# writes the backing field for you. Use it when there's no rule to check.
- `private set` lets other code read a property while only the class changes it, as with a team's `Wins`.
- A property with only a `get`, such as `public string Name { get; }`, is set in the constructor and never changes after that.
- A calculated property, such as `GamesPlayed => Wins + Losses`, works its value out each time it's read, so it never disagrees with the others.
- `new Team { Wins = 7, Losses = 3 }` is an object initializer: it sets public properties as the object is created.

Most properties don't check anything; they just hold a value. Writing a backing field and a `get` and `set` for each one would be a lot of typing for nothing, so C# has a shortcut.

## Auto-properties

An **auto-property** writes the backing field for you:

```csharp
Team team = new Team();
team.Name = "Georgia";
team.Wins = 7;

Console.WriteLine($"{team.Name}: {team.Wins} wins");

public class Team
{
    public string Name { get; set; } = "";
    public int Wins { get; set; }
}
```

```text
Georgia: 7 wins
```

`{ get; set; }` means "a property anyone can read and set, with a hidden field behind it". `= ""` gives it a starting value. (A `string` property needs one, or C# warns that it might be `null`.)

When you need a rule, as in the last lesson, write the full property. When you don't, use an auto-property: you can always change it to a full one later, and no calling code has to change.

## Read-only to the outside: private set

Often other code should be able to **read** a value, but only the object itself should **change** it. A team's wins should change only when a game is recorded, not because some other code assigned a number. Make the `set` private:

```csharp
Team team = new Team("Georgia");
team.RecordWin();
team.RecordWin();
team.RecordLoss();

Console.WriteLine($"{team.Name}: {team.Wins}-{team.Losses}");

public class Team
{
    public string Name { get; private set; }
    public int Wins { get; private set; }
    public int Losses { get; private set; }

    public Team(string name)
    {
        Name = name;
    }

    public void RecordWin()
    {
        Wins++;
    }

    public void RecordLoss()
    {
        Losses++;
    }
}
```

```text
Georgia: 2-1
```

Outside the class, `team.Wins = 50;` doesn't compile. The only way to change the record is through `RecordWin` and `RecordLoss`.

A property with **only** a `get`, such as `public string Name { get; }`, can be set only in the constructor, and never again.

## Calculated properties

Some values shouldn't be stored at all, because they follow from others. A team's winning percentage comes from its wins and losses. Store it separately and the two can disagree; calculate it, and they never can. A **calculated** (or derived) property has only a `get`, which works the value out each time it's read:

```csharp
Team team = new Team { Wins = 7, Losses = 3 };
Console.WriteLine($"Games played: {team.GamesPlayed}");
Console.WriteLine($"Winning percentage: {team.WinningPercentage}%");

team.Losses = 7;
Console.WriteLine($"Winning percentage now: {team.WinningPercentage}%");

public class Team
{
    public int Wins { get; set; }
    public int Losses { get; set; }

    public int GamesPlayed => Wins + Losses;

    public int WinningPercentage
    {
        get
        {
            if (GamesPlayed == 0)
            {
                return 0;
            }
            return Wins * 100 / GamesPlayed;
        }
    }
}
```

```text
Games played: 10
Winning percentage: 70%
Winning percentage now: 50%
```

- `=> Wins + Losses` is a short way to write a property with only a `get` whose whole job is one expression.
- When `Losses` changed, `WinningPercentage` changed with it: there's nothing to keep in step.

## Setting properties as you create: object initializers

`new Team { Wins = 7, Losses = 3 }` creates the object and then sets public properties in one statement. The curly braces after `new Team` are an **object initializer**. It works for any property with a public `set`.

## Check yourself

2 questions to try on the lesson page.

## So what

Choose each property's access on purpose: public `get` and `set` for plain values, `private set` for values only the object should change, and a calculated `get` for values that follow from others.

## Key terms

- [Auto-Implemented Property](https://www.ask-codey.com/glossary/auto-implemented-property)
- [Calculated Property](https://www.ask-codey.com/glossary/calculated-property)
- [Object Initializer](https://www.ask-codey.com/glossary/object-initializer)

## Cheat sheets

- [Auto-Properties and Read-Only Properties](https://www.ask-codey.com/cheat-sheets/properties-in-csharp-auto-properties-and-read-only-properties-cheat-sheet)

Source: https://www.ask-codey.com/lessons/properties-in-csharp-auto-properties-and-read-only-properties
