11. Encapsulation and Access Modifiers
Level: Beginner
- What encapsulation means
- Why data should be protected
- Use
privatefields - Use
publicproperties and methods - Validate data before storing
- Understand public, private, protected, and internal
Encapsulation means protecting data inside a class.
The class should not allow invalid changes from outside.
The Problem: Anyone Can Break Public Data
Wrong design:
public class FeeAccount
{
public decimal PaidAmount;
}
FeeAccount account = new FeeAccount();
account.PaidAmount = -5000.00m;
Problem:
Paid amount cannot be negative.
But public field allows it.
Encapsulation fixes this.
Quick Definitions
- Encapsulation - Hiding internal data and providing controlled access
- Data hiding - Keeping fields private so outside code cannot change them directly
- Access modifier - Keyword that controls who can access data (public, private, protected, internal)
- Private - Can be used only inside the same class
- Public - Can be accessed from outside the class
- Protected - Can be used in same class and child classes
- Property - Controlled way to read/write a field
- Getter -
getmethod that returns a value - Setter -
setmethod that changes a value with validation - Validation - Checking if data is valid before storing it
What is Encapsulation?
Encapsulation means:
Hide internal data.
Allow changes only through controlled methods/properties.
Example:
public class FeeAccount
{
private decimal _paidAmount;
public decimal PaidAmount
{
get { return _paidAmount; }
}
public void MakePayment(decimal amount)
{
if (amount <= 0)
{
Console.WriteLine("Invalid amount.");
return;
}
_paidAmount += amount;
}
}
Now outside code cannot directly set _paidAmount.
Access Modifiers
Access modifiers control who can access data or methods.
| Modifier | Meaning | Beginner Use |
|---|---|---|
public | Can be accessed from outside | Methods/properties users need |
private | Same class only | Internal fields |
protected | Same class and child classes | In inheritance |
internal | Same project only | Project-level helpers |
Beginner rule:
Keep fields private.
Expose only needed properties and methods as public.
Step 1: Private Field
private decimal _paidAmount;
This can be used only inside the same class.
Outside code cannot do this:
account._paidAmount = 1000;
Step 2: Public Read-Only Property
public decimal PaidAmount
{
get { return _paidAmount; }
}
Outside code can read:
Console.WriteLine(account.PaidAmount);
But cannot write:
account.PaidAmount = 5000; // error
Step 3: Public Method for Controlled Change
public void MakePayment(decimal amount)
{
if (amount <= 0)
{
Console.WriteLine("Invalid amount.");
return;
}
_paidAmount += amount;
}
Now payment can change only through MakePayment.
Full Example: Fee Account
Property Types
Auto Property
Use when no validation is needed.
public string Name { get; set; } = "";
Read-Only Property
Can read from outside, but cannot write.
public string StudentName { get; }
Full Property with Validation
Use when you need to check value before storing.
private double _percentage;
public double Percentage
{
get { return _percentage; }
set
{
if (value < 0 || value > 100)
{
throw new ArgumentException("Percentage must be between 0 and 100.");
}
_percentage = value;
}
}
Computed Property
Calculated from other values.
public decimal Balance
{
get { return _totalFees - _paidAmount; }
}
When You'll Use This in SMS
Every SMS entity protects its data.
FeeAccount example:
- Field:
private decimal _paidAmount(hidden) - Property:
public decimal PaidAmount { get; }(read-only) - Method:
public void MakePayment(decimal amount)(controlled)
Validation prevents bad data:
PaidAmount = -5000 -> Error (invalid)
PaidAmount = 150000 (more than fees) -> Error (invalid)
MakePayment(10000) -> Success (valid)
Real impact:
- Teacher cannot directly change Student percentage to 500% (invalid)
- Fee balance always calculated correctly, never manually set wrong
- Exam result cannot be negative
- Production SMS has validation in every class
Design principle:
- Keep fields private
- Expose only safe properties/methods
- Validate before storing data
Try This Now
Run the FeeAccount example above. Then experiment:
- Try directly accessing:
account._totalFees = 50000;(should error) - Call
account.MakePayment(15000);(should work) - Try
account.MakePayment(-2000);(should reject) - Check
account.Balance(should be calculated, not changeable) - Create StudentResult class with Percentage validation (0-100 only)
See how encapsulation prevents bad data.
Encapsulation explained: private, public, properties, validation, data protection. Video coming soon. Subscribe to NexCoding YouTube for updates.
Common Mistakes
Mistake 1: Public fields
Wrong:
public decimal PaidAmount;
Better:
private decimal _paidAmount;
public decimal PaidAmount { get { return _paidAmount; } }
Mistake 2: No validation
Wrong:
public double Percentage { get; set; }
This allows Percentage = 150.
Better:
public double Percentage
{
get { return _percentage; }
set
{
if (value < 0 || value > 100)
{
throw new ArgumentException();
}
_percentage = value;
}
}
Mistake 3: Making everything public
Only expose what other classes really need.
Mistake 4: Allowing direct balance change
Balance should be calculated, not manually assigned.
Best Practices
- Keep fields private.
- Use public properties for controlled access.
- Use methods to perform important actions.
- Validate data before storing it.
- Use read-only properties for values that should not change.
- Use computed properties for values like balance.
- Do not expose internal data unnecessarily.
Practice Task
Create a StudentResult class.
Rules:
- StudentName should be set in constructor.
- Percentage must be between 0 and 100.
- Result should be calculated as Pass/Fail.
- Outside code should not directly change Result.
Starter:
public class StudentResult
{
private double _percentage;
public string StudentName { get; }
public double Percentage
{
get { return _percentage; }
set
{
if (value < 0 || value > 100)
{
throw new ArgumentException("Invalid percentage.");
}
_percentage = value;
}
}
public string Result
{
get { return Percentage >= 35 ? "Pass" : "Fail"; }
}
public StudentResult(string studentName)
{
StudentName = studentName;
}
}
Quick Revision
| Question | Answer |
|---|---|
| What is encapsulation? | Protecting data inside class |
| Which modifier hides data? | private |
| Which modifier exposes data? | public |
| Why use properties? | Controlled access |
| Why validate in setter/method? | Prevent invalid data |
| What is computed property? | Value calculated from other values |
Encapsulation means hiding internal data and exposing only controlled access through properties and methods.
Private fields prevent outside code from changing data directly and incorrectly.
Properties allow validation and controlled read/write access.
A read-only property has only get, so outside code can read it but cannot change it.
A computed property does not store its own value. It calculates from other fields or properties.
Use ChatGPT, Claude, or Copilot to go deeper on C# encapsulation and access modifiers. Try these prompts:
"Explain encapsulation with a school fee account example""Give me 5 practice tasks for encapsulation""Explain public, private, protected, and internal simply""Quiz me with 5 beginner questions about encapsulation"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.