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

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:

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

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

public class Team
{
    public string Name { get; set; } = "";
    public int Wins { get; set; }
}
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:

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

Console.WriteLine(quot;{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++;
    }
}
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:

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

team.Losses = 7;
Console.WriteLine(quot;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;
        }
    }
}
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

Cheat sheets