C# Abstraction

Hiding complexity and showing only essentials

🎨 What is Abstraction?

Abstraction hides complex implementation details and shows only the necessary features. It focuses on what an object does rather than how it does it, using abstract classes and methods.


abstract class Animal {
    // Abstract method (no implementation)
    public abstract void MakeSound();
    
    // Regular method
    public void Sleep() {
        Console.WriteLine("Sleeping...");
    }
}

class Dog : Animal {
    public override void MakeSound() {
        Console.WriteLine("Woof!");
    }
}
                                    

Output:

Woof!

Sleeping...

Key Abstraction Concepts

📦

Abstract Class

Cannot be instantiated directly

abstract class Shape {
    // code here
}
🔧

Abstract Method

Must be implemented by child

public abstract 
void Calculate();
✅

Concrete Method

Has implementation in abstract class

public void Display() {
    // implementation
}
🎯

Override Required

Child must override abstract methods

public override 
void Calculate() { }

🔹 Abstract Class Basics

An abstract class in object-oriented programming acts as an incomplete blueprint that cannot be instantiated directly. It's designed to be inherited by other classes. Abstract classes can contain a mix of abstract methods (declarations without implementation, marked with `abstract`) and concrete methods (with full implementation). They define a common interface and partial functionality for a group of related subclasses. For example, an abstract `Shape` class can define an abstract `CalculateArea()` method and a concrete `Display()` method, forcing all derived shapes like `Circle` or `Square` to implement their own area calculation logic.

abstract class Vehicle {
    // Abstract method - no implementation
    public abstract void Start();
    
    // Concrete method - has implementation
    public void Stop() {
        Console.WriteLine("Vehicle stopped");
    }
}

class Car : Vehicle {
    // Must implement abstract method
    public override void Start() {
        Console.WriteLine("Car started with key");
    }
}

// Usage
Car myCar = new Car();
myCar.Start();
myCar.Stop();

Output:

Car started with key

Vehicle stopped

🔹 Abstract Methods

Abstract methods are method declarations within an abstract class that provide no implementation—only the signature. They are marked with the `abstract` keyword and end with a semicolon. Derived (non-abstract) classes must override and provide a concrete implementation for all inherited abstract methods. This enforces a contract, ensuring that all subclasses support a specific behavior while allowing them the flexibility to define how that behavior works. For instance, an abstract `DatabaseConnector` class might have an abstract `Connect()` method, implemented differently by `SqlConnector` and `MongoDbConnector` subclasses.

abstract class Shape {
    public abstract double GetArea();
    public abstract double GetPerimeter();
    
    public void Display() {
        Console.WriteLine($"Area: {GetArea()}");
        Console.WriteLine($"Perimeter: {GetPerimeter()}");
    }
}

class Circle : Shape {
    public double Radius = 5;
    
    public override double GetArea() {
        return 3.14 * Radius * Radius;
    }
    
    public override double GetPerimeter() {
        return 2 * 3.14 * Radius;
    }
}

// Usage
Circle circle = new Circle();
circle.Display();

Output:

Area: 78.5

Perimeter: 31.4

🔹 Real-World Example

Interfaces enable dependency injection and loosely coupled architectures. In payment processing, an IPaymentGateway interface allows switching between CreditCardProcessor or PayPalProcessor without changing core logic. The system validates and processes payments through the interface, adhering to the Open/Closed Principle. This makes applications testable, maintainable, and adaptable to new payment methods.

abstract class BankAccount {
    protected double balance;
    
    public BankAccount(double initialBalance) {
        balance = initialBalance;
    }
    
    // Abstract methods - must be implemented
    public abstract void Deposit(double amount);
    public abstract void Withdraw(double amount);
    
    // Concrete method - shared by all accounts
    public void CheckBalance() {
        Console.WriteLine($"Balance: ${balance}");
    }
}

class SavingsAccount : BankAccount {
    public SavingsAccount(double initial) : base(initial) { }
    
    public override void Deposit(double amount) {
        balance += amount;
        Console.WriteLine($"Deposited ${amount}");
    }
    
    public override void Withdraw(double amount) {
        if (balance >= amount) {
            balance -= amount;
            Console.WriteLine($"Withdrew ${amount}");
        }
    }
}

// Usage
SavingsAccount account = new SavingsAccount(1000);
account.Deposit(500);
account.Withdraw(200);
account.CheckBalance();

Output:

Deposited $500

Withdrew $200

Balance: $1300

🔹 Abstract Properties

Similar to abstract methods, abstract classes can also define abstract properties. These are property declarations without a getter or setter implementation in the abstract class. Derived classes must override them to provide their own accessors. This is useful when a property's value is fundamental to the class but its retrieval or assignment logic varies. For example, an abstract `Employee` class might have an abstract `Salary` property. The `FullTimeEmployee` subclass could calculate it as a fixed annual amount, while `ContractEmployee` might compute it based on hourly rate and hours worked, enforcing a consistent interface across different employee types.

abstract class Employee {
    public string Name;
    
    // Abstract property
    public abstract double Salary { get; set; }
    
    // Abstract method
    public abstract void Work();
}

class Developer : Employee {
    private double salary;
    
    public override double Salary {
        get { return salary; }
        set { salary = value; }
    }
    
    public override void Work() {
        Console.WriteLine($"{Name} is writing code");
    }
}

// Usage
Developer dev = new Developer();
dev.Name = "Alice";
dev.Salary = 75000;
dev.Work();
Console.WriteLine($"Salary: ${dev.Salary}");

Output:

Alice is writing code

Salary: $75000

🧠 Test Your Knowledge

Can you create an instance of an abstract class?