Skip to Content
Course content

23: Properties, Fields, and Auto-Properties

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Why can't I just make my variables public?

It's tempting. When you're first starting out, writing public int Health; feels faster than writing a whole property. But here is the problem: you're giving the rest of your program a blank check to mess with your object's internal state. If your Player class has a public health field, any other piece of code can set that health to -1,000,000 or 999,999,999, and your class has no way to stop it or react to it.

By using a property, you create a "gatekeeper." You keep the actual data (the field) private and expose a property that controls how that data is read or changed. I always tell my juniors: fields are for storage, properties are for access.

public class Player
{
    // This is a field. Private means it's hidden from the outside world.
    private int _health = 100;

    // This is the property. It's the public "face" of the field.
    public int Health
    {
        get { return _health; }
        set 
        { 
            // Now we have a place to put logic! 
            // We can prevent health from going below 0.
            if (value < 0) _health = 0;
            else _health = value;
        }
    }
}

What exactly is a "backing field" and do I always need one?

In the example above, _health is what we call a backing field. It's the actual spot in memory where the value lives. The property Health doesn't actually "hold" the value; it just provides the logic to get it out or put it in.

Do you always need one? No. Most of the time, you don't need that custom logic in the setter. You just want a value that can be read and written. Writing out a private field and a full property every single time is tedious and makes your files feel cluttered. That's where auto-properties come in.

If I'm not adding logic, what's the point of an auto-property?

You'll see this syntax everywhere: public string Name { get; set; }. This is an auto-property. When you write this, the C# compiler actually creates a hidden, private backing field for you behind the scenes. You don't see it, but it's there.

You might wonder, "If it's just doing the same thing as a public field, why bother?" Because of future-proofing. If you start with an auto-property and realize six months from now that you need to add validation (like making sure the name isn't empty), you can convert it to a full property with a backing field without breaking any other code that uses your class. If you had used a public field, changing it to a property would be a "breaking change" for anyone using your library.

public class Player
{
    // Clean, short, and professional.
    public string Username { get; set; } 
    
    // I can still have my complex property right next to it.
    public int Health { get; set; } = 100; 
}

How do I make a property that others can read, but not change?

This is one of the most common patterns I use. Often, you want the rest of the game to know what level a player is, but you don't want some random UI script to be able to set the player's level to 99.

You can do this by adding an access modifier to the setter. By marking the setter as private, you're telling C#: "Anyone can see this value, but only code inside this class can change it."

public class Player
{
    // Read-only to the outside world, writable inside the class.
    public int Level { get; private set; } = 1;

    public void GainExperience()
    {
        // This works because we are inside the class.
        Level++; 
    }
}

// In another class:
// player.Level = 10; // This would now cause a compiler error!



📋 Practical Task

Exercise: Implementing a Secure Wallet System

You are building a Wallet class for a digital store. Your goal is to ensure that the wallet's balance cannot be manipulated directly and cannot possibly be negative.

  • Create a Wallet class.
  • Add a private field to store the balance (e.g., _balance).
  • Create a public property called Balance. The get should return the balance, but the set should only update the balance if the provided value is 0 or greater. If the value is negative, it should be ignored.
  • Add an auto-property called OwnerName that can be read and written by anyone.
  • Add a property called WalletId that can be read by anyone, but can only be set within the Wallet class (private setter).
  • In your Main method, try to set the balance to a negative number and verify that it stays at its default value.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.