How to Use Abstract Class in C# with Example?

In object-oriented programming, abstract classes serve as foundational blueprints for other classes. In C#, abstract classes are used to encapsulate common functionalities for derived classes, yet they cannot be instantiated on their own. They are particularly useful when multiple classes share common methods or properties, but those classes will implement those methods or properties differently.

Using abstract classes in C# helps in reducing code duplication and encourages a cleaner, more maintainable codebase. They enforce a contract for the derived classes, specifying what methods or properties must be implemented, making the framework robust and consistent. It’s a strategic way to plan out class hierarchies and functionality upfront.

To understand the abstract classes in C# clearly, consider an example containing shapes like circles and rectangles. Each shape has a method to calculate area, but the actual formula differs for each shape. An abstract class Shape can define an abstract method CalculateArea without an implementation. The derived classes Circle and Rectangle then provide their respective implementations for CalculateArea. This approach allows the use of a common interface to work with various specific shapes, simplifying coding and improving flexibility.

Understanding Abstract Classes in C#

In C#, an abstract class is a foundational construct that cannot be instantiated on its own. Abstract classes provide a base for other classes to derive from. They can contain both abstract and concrete members, where abstract members are declared with the abstract keyword and have no implementation.

A class that inherits from an abstract class must implement all of its abstract members, or it must be declared abstract itself. Consider this as a contract: derived classes agree to furnish specifics for any abstract elements.

Abstract classes are particularly useful when multiple classes share common functionality but also have additional unique features. Rather than repeating shared code across classes, one can write the shared pieces within an abstract class.

Key Characteristics of Abstract Classes:

  • Cannot be instantiated directly
  • Used as a base class
  • Can contain abstract and non-abstract members
  • Provide a common definition of a base class that multiple derived classes can share

Example:

public abstract class Animal {
    public abstract void MakeSound();

    public void Eat() {
        Console.WriteLine("The animal is eating.");
    }
}

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

In this example, Animal is an abstract class with an abstract method MakeSound() and a concrete method Eat(). The Dog class inherits from Animal and provides its own implementation of MakeSound().

Implementing Abstract Classes

In C#, an abstract class serves as a blueprint for other classes. It can contain both complete (concrete) and incomplete (abstract) methods. Abstract classes cannot be instantiated directly, and they require subclasses to provide implementations for the abstract methods.

To define an abstract class, one uses the abstract keyword:

public abstract class Animal
{
    public abstract void Speak();
    
    public void Move()
    {
        // Concrete method with implementation
    }
}

In this example, Animal is an abstract class with one abstract method, Speak(), and one concrete method, Move().

A subclass can implement the abstract class as follows:

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

Here, the Dog class derives from Animal and provides an implementation for the Speak method.

KeywordUsage
abstractMarks a class or a method as abstract.
overrideProvides implementation for an inherited abstract method.

Rules for Abstract Classes:

  • An abstract class cannot be sealed.
  • It can contain constructors.
  • Abstract members cannot be private.
  • A non-abstract class derived from an abstract class must include actual implementations of all inherited abstract methods and accessors.

A class that inherits from an abstract class but does not implement all abstract methods must also be declared as abstract.

Abstract Class Example

In C#, an abstract class serves as a blueprint for other classes. It cannot be instantiated on its own and must be inherited by a child class. Here is a simple example:

Step 1: Define an Abstract Class

public abstract class Shape
{
    // Abstract method with no implementation
    public abstract int GetArea();
}

The Shape class is declared abstract and contains an abstract method GetArea.

Step 2: Implement the Abstract Class

public class Circle : Shape
{
    private int radius;

    public Circle(int r)
    {
        radius = r;
    }
    
    // Implementing the abstract method
    public override int GetArea()
    {
        return (int)(Math.PI * radius * radius);
    }
}

The Circle class inherits from Shape and implements the abstract method GetArea.

Step 3: Usage Example

Shape myCircle = new Circle(5);
int area = myCircle.GetArea();
// Output the area
Console.WriteLine("Area of the circle: " + area);

An instance of Circle is created and used to calculate the area. The output is then printed to the console.

By following these steps, one constructs a practical hierarchy that promotes reusability and abides by the object-oriented design principle of abstraction.

Abstract Class vs Interface

Abstract classes and interfaces in C# are used to achieve abstraction, which allows for creating blueprints for other classes. However, they serve different purposes and have their unique characteristics.

An abstract class:

  • Can include both abstract (unimplemented) and concrete (implemented) methods.
  • Allows constructors and destructors.
  • Permits fields, properties, and methods with access modifiers.
  • Supports method implementations and can maintain state through fields.

An interface:

  • Contains only abstract method signatures (unimplemented).
  • Cannot contain fields, constructors, destructors, or any concrete methods.
  • Allows properties, but they cannot maintain state.
  • Acts as a contract and ensures a class implementing the interface adheres to a specific structure.
FeatureAbstract ClassInterface
MethodsCan have both abstract and fully implemented methods.Only contains method signatures (abstract).
FieldsCan have fields.Cannot contain fields.
Constructors/DestructorsPermitted.Not allowed.
Access ModifiersSupports public, protected, private, etc.Members are implicitly public.
ImplementationCan hold some implementation details.Cannot contain implementation.
InheritanceSingle inheritance (a class can only inherit from one).Supports multiple inheritance (through interfaces).

In C#, a class can inherit from one abstract class but can implement multiple interfaces. This allows a class to follow various contracts (interfaces), while instantiation logic and shared method implementations are provided by an abstract class. It is the developer’s responsibility to decide when to use an abstract class and when to use an interface based on the design requirements.

Best Practices for Abstract Classes

When designing software using C#, abstract classes serve as a blueprint for other classes. To ensure clarity and maintainability in code:

  • Define a Clear Purpose: Abstract classes should have a distinct and clear purpose. They are intended to be extended, so their role as a foundational element must be well-defined.
  • Use Abstract Methods Sparingly: Only include abstract methods when they enforce necessary behavior for the subclasses. Excessive use can lead to a rigid design, negatively impacting flexibility.
  • Non-Abstract Methods: It is permissible for abstract classes to have concrete methods. These should provide common functionality for all subclasses, reducing code duplication. Method Type Usage Guidance Abstract Methods Enforces subclasses to implement these methods Virtual Methods Allows subclasses to override if necessary, providing a default implementation Concrete Methods Implements behavior that is common across all subclasses, should not expect to be overridden
  • Minimize Class Members: Abstract classes should not be overly bloated with members. Include only what is essential for the class hierarchies that will derive from it.
  • Accessibility: Members that subclasses need to access should be marked as protected rather than private. This ensures that subclasses can access necessary properties and methods while still hiding them from external access.
  • Naming Conventions: Use intuitive naming to improve readability and understanding of the class’s purpose. For example, prefixing the name with Abstract or Base can be helpful; such as AbstractShape or BaseVehicle.

Advanced Usage of Abstract Classes

In C#, abstract classes are foundational when one needs to establish a template for a group of subclasses. They enable polymorphism, ensuring that each subclass implements its own version of the abstract class’s methods. A developer can take advanced utilization of abstract classes by employing them in complex inheritance hierarchies or as a means to provide common functionality for unrelated classes through interface-like patterns.

When an abstract class inherits from another abstract class, it can either implement or further abstract the inherited members. This layered approach allows for a fine-grained control over the inheritance hierarchy. Abstract members can be coupled with access modifiers such as protected or internal to restrict the visibility of those members.

Here’s an illustrative snippet:

public abstract class Vehicle
{
    public abstract void Move();
}

public abstract class Car : Vehicle
{
    public override abstract void Move(); // Car provides additional constraints.
    public abstract void StartEngine(); // Car-specific functionality
}

public class Sedan : Car
{
    public override void Move()
    {
        // Implementation specific to Sedan
    }

    public override void StartEngine()
    {
        // Start a Sedan engine
    }
}

Another advanced use is employing abstract class members to enforce a design pattern. Consider the Template Method pattern, where an abstract class defines the structure of an algorithm, and its concrete subclasses implement the algorithm steps.

For example:

public abstract class DataProcessor
{
    // Template Method
    public void ProcessData()
    {
        ReadData();
        ProcessReadData();
        WriteData();
    }

    protected abstract void ReadData();
    protected abstract void ProcessReadData();
    protected abstract void WriteData();
}

In this scenario, subclasses will define the specific details of data reading, processing, and writing operations, while the overall algorithm remains consistent across different types of data processors. This approach reduces code duplication and promotes a cleaner, more organized design.

Conclusion

Abstract classes in C# serve as a blueprint for other classes. They are instrumental for code reusability and establishing a contract for derived classes. When implementing an abstract class:

  • Classes that derive from an abstract class must implement all its abstract members.
  • Access modifiers such as public, protected, and private define the visibility of abstract members to inheriting classes.
  • Abstract members cannot have an implementation, meaning they simply declare the method’s signature.

In practice, one should:

  • Use abstract classes when multiple classes share common functionality, but require different implementations.
  • Avoid creating instances of abstract classes directly, as they are meant to be subclassed.
  • Remember that abstract classes can include both abstract and concrete members.

In this C# tutorial, I have explained how to work with Abstract Class in C# with a few examples.

You may also like: