Lesson 5
Understanding Abstraction in C#
Understanding Abstraction

Welcome back! Previously, you delved into polymorphism and learned how to create more flexible code structures using classes and inheritance. In this session, we will explore a crucial aspect of Object-Oriented Programming in C#: abstract classes and abstract methods.

What is an Abstract Class?

An abstract class in C# is a class that cannot be instantiated directly. Think of it as a blueprint for other classes. It can include abstract methods that are declared without implementation and non-abstract methods that have implementation. However, an abstract class can also be entirely free of methods initially.

To illustrate this, let's create an abstract class using the abstract keyword:

C#
1// Defining an abstract class 2public abstract class Shape 3{ 4 // ... 5}

This Shape class serves as a blueprint. Subclasses can inherit from Shape and add specific attributes and behaviors.

Implementing Abstract Methods

Now that you understand what an abstract class is, let's add abstract methods to our Shape class. An abstract method acts as a placeholder without any implementation, serving as a rule that subclasses must follow. It enforces consistency across subclasses while allowing each to fulfill the required behavior uniquely.

C#
1public abstract class Shape 2{ 3 // Defining abstract methods 4 public abstract double Area(); 5 public abstract double Perimeter(); 6}

Subclasses of Shape must implement these abstract methods.

Concrete Class: Circle

To see abstract methods in action, let's create a concrete class called Circle that inherits from Shape. The Circle class uses its constructor to initialize the radius and overrides both methods to provide specific implementations for calculating its area and perimeter.

C#
1public class Circle : Shape 2{ 3 public double Radius { get; set; } 4 5 public Circle(double radius) 6 { 7 Radius = radius; 8 } 9 10 // Overridden method to calculate the area of the circle 11 public override double Area() 12 { 13 return Math.PI * Math.Pow(Radius, 2); 14 } 15 16 // Overridden method to calculate the perimeter of the circle 17 public override double Perimeter() 18 { 19 return 2 * Math.PI * Radius; 20 } 21}
Concrete Class: Rectangle

Similarly, we can create another concrete class called Rectangle that also inherits from Shape. The Rectangle class initializes its width and height in the constructor and implements methods to compute its area and perimeter.

C#
1public class Rectangle : Shape 2{ 3 public double Width { get; set; } 4 public double Height { get; set; } 5 6 public Rectangle(double width, double height) 7 { 8 Width = width; 9 Height = height; 10 } 11 12 // Overridden method to calculate the area of the rectangle 13 public override double Area() 14 { 15 return Width * Height; 16 } 17 18 // Overridden method to calculate the area of the rectangle 19 public override double Perimeter() 20 { 21 return 2 * (Width + Height); 22 } 23}
Using Abstract Classes

To see how abstract classes are used in practice, let’s examine the Main method. Here, we create instances of Circle and Rectangle, and their areas and perimeters are printed to the console. This demonstrates the concrete implementations in each subclass.

C#
1class Program 2{ 3 static void Main() 4 { 5 Circle circle = new Circle(5); 6 Rectangle rectangle = new Rectangle(4, 6); 7 8 Console.WriteLine($"Circle Area: {circle.Area()}, Perimeter: {circle.Perimeter()}"); 9 // Output: Circle Area: 78.53981633974483, Perimeter: 31.41592653589793 10 Console.WriteLine($"Rectangle Area: {rectangle.Area()}, Perimeter: {rectangle.Perimeter()}"); 11 // Output: Rectangle Area: 24, Perimeter: 20 12 13 Shape shape = new Circle(3); 14 Console.WriteLine($"Shape Area: {shape.Area()}, Perimeter: {shape.Perimeter()}"); 15 // Output: Shape Area: 28.274333882308138, Perimeter: 18.84955592153876 16 } 17}

Note that we can use a reference to the Shape class to hold instances of its subclasses, demonstrating polymorphism and allowing for more flexible, reusable code. Additionally, the Shape class itself cannot be instantiated directly; only its subclasses with concrete method implementations can be. This ensures a consistent interface, improving code maintainability and readability.

Conclusion

Abstract classes and methods are powerful tools in C#'s OOP arsenal. They allow you to define a blueprint for a group of related classes, ensuring that all subclasses follow a specific interface. This promotes consistency and reliability in your code. By mastering abstract base classes and abstract methods, you can create more organized, maintainable, and scalable software.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.