intermediate18 min

Encapsulation and Access Modifiers

Controlling visibility with public, private, protected, and internal.

What you'll learn

  • Explain what each of public, private, protected, and internal controls
  • Use a private backing field with a public property to enforce an invariant
  • Explain why encapsulation matters for keeping an object's internal state valid

Explanation

C# has four everyday access modifiers controlling where a member (field, property, method, or the type itself) can be seen from:

  • public -- accessible from anywhere.
  • private -- accessible only from inside the same class (the default if you omit a modifier on a class member).
  • protected -- accessible from the declaring class and any class that derives from it, but not from unrelated code.
  • internal -- accessible from anywhere in the same assembly (roughly, the same compiled project), but not from other projects that reference it.

Encapsulation is the practice of keeping a type's internal data private and exposing controlled access through public members (properties and methods) that can enforce rules. A private field with a public read-only property (public decimal Balance => balance;, an expression-bodied property) lets outside code read a value freely while making it impossible to set that value except through methods you control, like a Deposit method that can reject a negative or zero amount.

Encapsulation is about hiding implementation details behind a controlled, stable public surface -- so a type's internal storage can change later without breaking any code that depends on it, as long as the public members keep their meaning.

Guided lab

Fill in the blank: a private backing field

C#Not executed
This lab does not run in your browser or on VisaSparkSchools's servers. Read the code, fill in the missing piece, then reveal the completed code and its expected output.

Fill in the missing access modifier, then predict the output.

using System;

public class BankAccount
{
    ____ decimal balance;

    public BankAccount(decimal initialBalance)
    {
        balance = initialBalance;
    }

    public decimal Balance => balance;

    public void Deposit(decimal amount)
    {
        if (amount > 0)
        {
            balance += amount;
        }
    }
}

BankAccount account = new BankAccount(100m);
account.Deposit(50m);
Console.WriteLine($"Balance: {account.Balance}");

Stuck? Get a hint.

Common mistakes

  • Making every field `public` for convenience, losing the ability to validate or change how a value is stored later without breaking every caller.
  • Confusing `protected` (visible to derived classes) with `internal` (visible anywhere in the same assembly) -- they control very different audiences.
  • Forgetting that a class member with no access modifier at all defaults to `private`, not `public`.

Knowledge check

Knowledge check

1. Which access modifier makes a member visible only inside its own declaring class?
2. Which access modifier is visible to a derived class but not to unrelated code?
3. Why is it useful to keep a field `private` and expose it through a public property or method instead?

Takeaway

Default to `private` fields with controlled `public` access through properties and methods -- it lets you enforce invariants and change internal storage later without breaking any code that depends on the type.

Summary

public/private/protected/internal control member visibility at increasing scope; encapsulation keeps internal state private and exposes only a controlled, validated public surface.

References

Your notes

Notes save automatically.