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
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
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.
Finished this lesson?
Mark it complete to track your progress and schedule a future review.
AI tutor
The optional AI tutor isn't enabled in this deployment. All lessons, exercises, quizzes, and search work fully without it.