NDepend Blog

Improve your .NET code quality with NDepend

Abstract Class vs Interface in C#

April 5, 2024 7 minutes read

Abstract Class vs Interface in CSharp

Abstract Class vs Interface in C# is a fundamental trade-off to master. Understanding the distinction between each option is fundamental for crafting flexible and maintainable code. This ultimate guide aims to shed light on the syntax, pros and cons, along with the preferences of experienced programmers, helping you make informed decisions in your programming endeavors.

What is an Abstract Class in C#?

An abstract class in C# is a special type of class that cannot be instantiated on its own and serves as a blueprint for other classes. It can contain fields and properties and various kinds of methods:

  • An abstract method is declared in an abstract class without an implementation, leaving it to derived classes to provide specific functionalities.
  • A concrete method provides an implementation shared by all sub-classes
  • Virtual methods are in the middle:
    • Like a concrete method, it provides a default implementation shared by all sub-classes
    • Like an abstract method, it can optionally be overridden in sub-classes

Understand that abstract classes cannot be marked as sealed, which means they are designed to be extended by other classes. Like for example the class Square is a derived class of ShapeBase abstract class.

Pros:

  1. Code Sharing through Implementation: Abstract classes allow you to provide some method implementations that subclasses can use or override.
  2. State Sharing: They can hold state (fields) and have a constructor, enabling more structured data sharing among subclasses.
  3. Versioning: Easier to evolve since you can add new concrete methods without breaking existing implementations.

Cons:

  1. Single Inheritance: A class can inherit from only one abstract class, limiting flexibility.
  2. Heavier Structure: More overhead than interfaces, as they can carry state and behavior.

What is an Interface in C#?

An interface in C# defines a contract or a blueprint that classes can implement. It specifies a set of method signatures (and properties, events, indexers) without providing an implementation. Classes that implement an interface must provide an implementation for all its members.

Pros:

  1. Multiple Implementations: A class can implement multiple interfaces, offering more flexibility and avoiding the limitations of single inheritance.
  2. Loose Coupling: Interfaces are ideal for defining modular APIs, making your code more adaptable and testable.
  3. Clear Contracts: They provide a clear separation of what a class should do, without dictating how it should do it.
  4. Testability: Numerous interfaces are introduced to simplify testing by mocking certain functionalities, allowing the tests to focus on the code that consumes these interfaces.

Cons:

  1. No Implementation: Interfaces cannot provide any method implementation, which can lead to redundancy if different classes use similar implementations.
  2. No State: They cannot hold state, which might require additional structures to share state among classes.

Vocabulary

Before continuing let’s underline the vocabulary.

  • We say that a class derives from a base class (abstract or not) while a class implements an interface.
  • We say that a class is a derived class or a subclass of a base class (abstract or not) while a class is an implementation of an interface.

Common Points and Differences

When comparing abstract classes and interfaces in C#, it’s essential to recognize both their commonalities and distinctions. Here’s a breakdown:

Common Points

  • Abstraction: Both are a way to abstract the real object class in the client code. The client code can work with an array of ShapeBase of or an array of IShape. In both cases, the array can contain Square objects, Circle objects, and Triangle objects. Calling the method  Translate() on all these shapes in a foreach loop will translate them all, no matter what they are.
  • Contract Definition: Both define a contract that subclasses or implementing classes must adhere to.
  • No Instantiation: Neither abstract classes nor interfaces can be instantiated directly; they serve as a blueprint. You can obtain a reference typed with ShapeBase or IShape by instantiating a concrete shape like in:  ShapeBase shape = new Square();
  • Method Declaration: Both can declare methods that must be implemented by inheriting or implementing classes.

Differences

  • Semantically Different:
    • Abstract Class: It typically serves as a foundational framework for related classes, housing shared implementations that these classes can utilize.
    • Interface: It is used to define a capability for classes like being disable, serializable or cloneable, which do not necessarily have to be closely related to one another.
  • Method Implementation:
    • Abstract Class: Can provide a mix of implemented and abstract methods.
    • Interface: Prior to C# 8.0, could only declare methods without providing an implementation. Starting with C# 8.0, interfaces can provide default implementations for methods.
  • State and Constructors:
    • Abstract Class: Can hold state (fields) and have constructors.
    • Interface: Cannot hold state or have constructors.
  • Inheritance:
    • Abstract Class: A class can inherit from only one abstract class, supporting the concept of single inheritance.
    • Interface: A class can implement multiple interfaces, facilitating multiple inheritances in terms of behavior.
  • Access Modifiers:
    • Abstract Class: Members can have access modifiers (public, protected, etc.).
    • Interface: Until C# 7.2, all members are implicitly public. Starting from C# 8.0, interfaces can define access modifiers for members.
  • Versioning:
    • Abstract Class: Adding a new abstract method to an abstract class can break existing subclasses.
    • Interface: Prior to C# 8.0, adding a new method to an interface would break implementing classes. With the introduction of default implementations in C# 8.0, interfaces now offer more flexibility for versioning.

Abstract Class vs Interface: When to Use Which?

Choosing between an abstract class and an interface depends on your specific scenario:

  • Use an abstract class when you need to share code among related classes, when your classes should inherit behavior as well as the interface, or when you anticipate changes to the abstract class that do not necessarily require changes to child classes.
  • Opt for an interface when you need to define a contract for classes that are unrelated, when you want to ensure that implementing classes provides specific functionalities, or when flexibility is paramount, allowing a class to implement multiple interfaces.

Advantages of Each Over the Other

  • Abstract Class:
    • Suitable for scenarios where you want to share code and enforce a certain structure across subclasses.
    • Allows the addition of new methods without breaking existing implementations.
  • Interface:
    • Offers the utmost flexibility, enabling multiple interface implementations within a single class.
    • Facilitates the development of loosely coupled systems, making your code more modular and testable.

What Seasoned C# Programmers Are Choosing

Prefer interfaces over abstract classes

Practical experience reveals that choosing an interface is generally a more advantageous choice than opting for a base class. The reasons are twofold:

  • Implementing an interface usually involves a lower level of commitment compared to inheriting from an abstract class. A Square class can implement both interfaces IShape and ISerializable. However, it cannot derive from both abstract classes ShapeBase and SerializableBase.
  • Frequently, inheriting code from an abstract class turns out to be more of a burden than a benefit. This difficulty arises from the complexity of designing a suitable abstract class, which demands experience and a thorough comprehension of the problem domain.

Sharing Code: Favor composition over inheritance

Real-world experience indicates that using abstract classes for sharing code is frequently suboptimal. The principle of favoring composition over inheritance is a well-established guideline in Object-Oriented Programming (OOP) due to several compelling reasons:

  • Dynamic Composition: Objects can change their behaviors at runtime by incorporating different objects with distinct behaviors. This is something inheritance cannot easily support since an inherited class is statically bound to its superclass.
  • Enhance Reusability: Composition allows for more granular reuse of small and decoupled objects, making it easier to understand, maintain, and reuse individual components.
  • Loose Coupling: With composition, objects are less tightly bound to each other than through inheritance. This loose coupling promotes encapsulation and makes the system more modular and easier to change.
  • Encapsulating Behavior: Composition enables encapsulating behavior within classes that can be easily composed into other objects without exposing the internal implementation details, preserving encapsulation.

Conclusion

In conclusion, both abstract classes and interfaces are powerful tools in a C# programmer’s arsenal, each with its own set of advantages and suitable use cases. However, during your C# programming career you will create many more interfaces than abstract classes. This is why when in doubt, it’s recommended to prefer interfaces over abstract classes. If the initial choice proves to be incorrect over time, refactoring an interface into a base class is a significantly simpler refactoring task than doing the reverse.