Skip to main content

11. Encapsulation and Access Modifiers

Level: Beginner

ℹ️ What You'll Learn
  • What encapsulation means
  • Why data should be protected
  • Use private fields
  • Use public properties 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 - get method that returns a value
  • Setter - set method 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.

ModifierMeaningBeginner Use
publicCan be accessed from outsideMethods/properties users need
privateSame class onlyInternal fields
protectedSame class and child classesIn inheritance
internalSame project onlyProject-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

💻 Try It — Console App
💡 Paste into Program.cs and press F5⌥ GitHub
FeeAccount account = new FeeAccount("Sahasra Kumar", 30000.00m);

account.MakePayment(10000.00m);
account.MakePayment(5000.00m);
account.MakePayment(-2000.00m);

account.PrintStatement();

public class FeeAccount
{
private decimal _totalFees;
private decimal _paidAmount;

public string StudentName { get; }

public decimal TotalFees
{
get { return _totalFees; }
}

public decimal PaidAmount
{
get { return _paidAmount; }
}

public decimal Balance
{
get { return _totalFees - _paidAmount; }
}

public FeeAccount(string studentName, decimal totalFees)
{
if (string.IsNullOrWhiteSpace(studentName))
{
throw new ArgumentException("Student name is required.");
}

if (totalFees <= 0)
{
throw new ArgumentException("Total fees must be positive.");
}

StudentName = studentName;
_totalFees = totalFees;
}

public void MakePayment(decimal amount)
{
if (amount <= 0)
{
Console.WriteLine("Invalid payment amount.");
return;
}

if (amount > Balance)
{
Console.WriteLine("Payment is greater than balance.");
return;
}

_paidAmount += amount;
Console.WriteLine($"Payment accepted: {amount}");
}

public void PrintStatement()
{
Console.WriteLine("=== Fee Statement ===");
Console.WriteLine($"Student: {StudentName}");
Console.WriteLine($"Total Fees: {TotalFees}");
Console.WriteLine($"Paid Amount: {PaidAmount}");
Console.WriteLine($"Balance: {Balance}");
}
}

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:

  1. Try directly accessing: account._totalFees = 50000; (should error)
  2. Call account.MakePayment(15000); (should work)
  3. Try account.MakePayment(-2000); (should reject)
  4. Check account.Balance (should be calculated, not changeable)
  5. Create StudentResult class with Percentage validation (0-100 only)

See how encapsulation prevents bad data.


ℹ️ Video Tutorial

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

  1. Keep fields private.
  2. Use public properties for controlled access.
  3. Use methods to perform important actions.
  4. Validate data before storing it.
  5. Use read-only properties for values that should not change.
  6. Use computed properties for values like balance.
  7. 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

QuestionAnswer
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

🎯 Q1: What is encapsulation?

Encapsulation means hiding internal data and exposing only controlled access through properties and methods.

🎯 Q2: Why should fields be private?

Private fields prevent outside code from changing data directly and incorrectly.

🎯 Q3: Why use properties instead of public fields?

Properties allow validation and controlled read/write access.

🎯 Q4: What is a read-only property?

A read-only property has only get, so outside code can read it but cannot change it.

🎯 Q5: What is a computed property?

A computed property does not store its own value. It calculates from other fields or properties.


🤖Use AI to Learn Faster
⚠️ Important for beginners: Do NOT use AI to write your code yet. Type every example yourself. Your brain learns by doing, not by reading AI output. Use AI only to explain and quiz you — not to code for you. Once you have strong fundamentals, AI becomes a powerful productivity tool for repetitive tasks.

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.

Next Article

Inheritance - Reusing Code with Parent and Child Classes ->

nexcoding.in