Lesson 14 — Protecting Data
Encapsulation
C# access modifiers and properties protect internal state. The internal modifier adds an assembly-level scope that Java does not have.
Access Modifiers
| Modifier | Accessible from |
|---|---|
private | Containing class only |
protected | Class and derived classes |
internal | Same assembly (DLL/EXE) |
protected internal | Same assembly or derived classes |
public | Everywhere |
CSHARP — Encapsulated Learner
public class Learner {
private string _name;
private int _age;
private double _mark;
public Learner(string name, int age, double mark) {
Name = name; // use properties — runs validation
Age = age;
Mark = mark;
}
public string Name {
get => _name;
set {
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("Name cannot be empty.");
_name = value.Trim();
}
}
public int Age {
get => _age;
set {
if (value < 15 || value > 80)
throw new ArgumentOutOfRangeException(nameof(Age));
_age = value;
}
}
public double Mark {
get => _mark;
set {
if (value < 0 || value > 100)
throw new ArgumentOutOfRangeException(nameof(Mark));
_mark = value;
}
}
// Internal helper — not visible outside the class:
private string GradeLabel() => Mark switch {
>= 80 => "Distinction", >= 60 => "Merit",
>= 50 => "Pass", _ => "Not yet competent"
};
public void PrintProfile() =>
Console.WriteLine($"{Name} | Age {Age} | {Mark:F1}% | {GradeLabel()}");
}
CSHARP — Using the class
var l = new Learner("Thandi", 21, 74.5);
l.PrintProfile();
l.Mark = 82.0; // setter runs
try { l.Age = -5; }
catch (ArgumentOutOfRangeException ex) {
Console.WriteLine($"Caught: {ex.ParamName}");
}
// Direct field access is impossible:
// l._mark = 150; // compile error — private
Practice Task
Your Turn
Make all fields in a BankAccount class private. Add: read-only AccountNumber (get; init;), read/write HolderName (validates non-empty), read-only Balance (get; private set;), and methods Deposit(decimal amount) and Withdraw(decimal amount) that update Balance only after validation.
Common Mistakes
- Public fields — always prefer properties in C#.
- Skipping validation in setters — if you validate in the constructor but use
_field = valueinstead of calling the property setter, you bypass your own validation. - Same name for backing field and property — use
_agefor the field andAgefor the property. - Making internal helper methods public — keep the public surface area minimal.
Professional Tip
Encapsulation is not bureaucracy — it is a contract. The class promises: 'my data is always valid'. That promise only holds if all mutation goes through the property setters.
Mini Quiz
Which modifier restricts access to the same assembly (DLL/EXE)?
internal restricts to the containing assembly — a uniquely C# concept. It is the default for class-level types if no modifier is specified.