Understanding C# Abstraction

Abstraction in C# is a key concept of object-oriented programming (OOP) that allows you to define the structure of objects without revealing the implementation details. Abstraction focuses on what an object does rather than how it does it. This can be achieved using abstract classes and interfaces.

Key Topics

What is Abstraction?

Abstraction is the concept of hiding the implementation details and showing only the essential features of an object. In C#, abstraction can be achieved using abstract classes and interfaces.

Example: Abstraction Overview

public abstract class Animal
{
    // Abstract method (no implementation)
    public abstract void MakeSound();

    // Non-abstract method (with implementation)
    public void Sleep()
    {
        Console.WriteLine("Sleeping...");
    }
}

public class Dog : Animal
{
    // Implement abstract method
    public override void MakeSound()
    {
        Console.WriteLine("Dog barks");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Dog dog = new Dog();
        dog.MakeSound(); // Output: Dog barks
        dog.Sleep();     // Output: Sleeping...
    }
}

Output:

Dog barks
Sleeping...
                        

Explanation: In this example, the Animal class is abstract and contains both an abstract method (MakeSound()) and a non-abstract method (Sleep()). The Dog class provides an implementation for the abstract method. The non-abstract method can be called without overriding it.

Abstract Classes

An abstract class in C# is a class that cannot be instantiated. It is used to define the structure of an object, but it may contain both abstract methods (which must be implemented by derived classes) and non-abstract methods (which can have a default implementation).

Example: Abstract Class Usage

public abstract class Shape
{
    // Abstract method (no implementation)
    public abstract double CalculateArea();

    // Non-abstract method
    public void DisplayShape()
    {
        Console.WriteLine("This is a shape.");
    }
}

public class Circle : Shape
{
    public double Radius { get; set; }

    // Implement the abstract method
    public override double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Circle circle = new Circle { Radius = 5 };
        circle.DisplayShape();               // Output: This is a shape.
        Console.WriteLine($"Area: {circle.CalculateArea()}");  // Output: Area: 78.54
    }
}

Output:

This is a shape.
Area: 78.54
                        

Explanation: The abstract class Shape defines an abstract method CalculateArea(), which is implemented by the derived class Circle. The non-abstract method DisplayShape() is inherited and can be used without any changes.

Abstract Methods

An abstract method is a method declared in an abstract class that does not have a body and must be implemented by derived classes. Abstract methods are used to enforce that certain functionality must be provided by any subclass.

Example: Abstract Methods

public abstract class Vehicle
{
    // Abstract method
    public abstract void StartEngine();
}

public class Car : Vehicle
{
    // Implement abstract method
    public override void StartEngine()
    {
        Console.WriteLine("Car engine started.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Car car = new Car();
        car.StartEngine(); // Output: Car engine started.
    }
}

Output:

Car engine started.
                        

Explanation: The abstract class Vehicle contains an abstract method StartEngine(), which must be implemented by any derived class. In this case, the Car class provides its own implementation.

Interfaces and Abstraction

Interfaces in C# also provide a way to achieve abstraction. An interface defines a contract, meaning any class that implements the interface must provide implementations for all of its members. Unlike abstract classes, a class can implement multiple interfaces.

Example: Using Interfaces for Abstraction

public interface IMovable
{
    void Move(); // Interface method (no implementation)
}

public class Car : IMovable
{
    // Implement interface method
    public void Move()
    {
        Console.WriteLine("The car is moving.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        IMovable car = new Car();
        car.Move(); // Output: The car is moving.
    }
}

Output:

The car is moving.
                        

Explanation: The interface IMovable defines a method Move() that must be implemented by any class that implements the interface. In this example, the Car class implements the Move() method, providing a specific behavior.

Abstraction in Action

Abstraction allows you to focus on the essential behavior of objects while hiding the complexity of their implementation. By using abstract classes and interfaces, you can ensure that specific functionality is provided by derived classes or classes that implement interfaces.

Example: Abstraction in Action

public abstract class Appliance
{
    public abstract void TurnOn(); // Abstract method
}

public class WashingMachine : Appliance
{
    // Implement abstract method
    public override void TurnOn()
    {
        Console.WriteLine("Washing machine turned on.");
    }
}

public class Refrigerator : Appliance
{
    // Implement abstract method
    public override void TurnOn()
    {
        Console.WriteLine("Refrigerator turned on.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Appliance washer = new WashingMachine();
        Appliance fridge = new Refrigerator();

        washer.TurnOn();  // Output: Washing machine turned on.
        fridge.TurnOn();  // Output: Refrigerator turned on.
    }
}

Output:

Washing machine turned on.
Refrigerator turned on.
                        

Explanation: In this example, the abstract class Appliance defines an abstract method TurnOn(). Both the WashingMachine and Refrigerator classes provide their own implementations of the TurnOn() method. This demonstrates how abstraction allows different objects to share a common interface while having distinct implementations.

Key Takeaways

  • Abstraction hides the complexity of implementation and shows only the essential details.
  • Abstract classes allow you to define methods without implementation, leaving it to the derived classes to provide their own functionality.
  • Interfaces define a contract that must be fulfilled by any class that implements them, allowing for multiple implementations.
  • Abstraction promotes the separation of concerns, making code more maintainable and easier to understand.