Back to Blog
C#

C# Abstract Class Constructor: How It Works

c# abstract class constructor: Understand C# abstract class constructors: how they are invoked by derived classes, how to pass parameters, and where they fit in object...

C#Abstract ClassesConstructorsInheritanceObject Initialization
Diagram showing an abstract class constructor being invoked from a derived class constructor during object initialization.

In C#, an abstract class can have constructors even though you cannot directly instantiate it with new. The c# abstract class constructor is invoked when a derived class instance is created, giving you a place to initialize shared fields and enforce invariants before the derived constructor body runs.

Why an Abstract Class Needs a Constructor

An abstract class often holds state that every derived class should have. For example, a repository base class may need a connection string, a logger, or a configuration object. Without a constructor, you would have to initialize those fields in every derived class, which duplicates logic and makes future changes more error-prone.

A constructor on the abstract class lets you centralize that initialization. The derived class only needs to pass the required values, and the base constructor takes care of the rest. This is especially useful when the fields are readonly or when validation must happen before the derived class can use them.

public abstract class Repository { protected readonly string ConnectionString; protected Repository(string connectionString) { if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentException("Connection string cannot be empty.", nameof(connectionString)); ConnectionString = connectionString; } }

Here the constructor validates the input and stores it in a readonly field. Any derived repository will inherit this behavior automatically.

How the Base Constructor Is Invoked

When you create an instance of a derived class, the runtime must call a constructor on every class in the inheritance chain. Even though you cannot write new AbstractClass(), the abstract class constructor is still called as part of the derived object's construction.

If the abstract class has a parameterless constructor and the derived class does not explicitly call a base constructor, the compiler inserts a call to base(). If the abstract class only has a parameterized constructor, the derived class must call it explicitly using : base(...).

public class CustomerRepository : Repository { public CustomerRepository(string connectionString) : base(connectionString) { } }

The : base(connectionString) syntax passes the value to the abstract class constructor. Without it, the code would not compile because there is no parameterless constructor to call.

Declaring Parameterized Constructors

Parameterized constructors on an abstract class are common when the base class needs configuration data. The derived class constructor receives its own parameters and forwards the relevant ones to the base constructor.

public abstract class ServiceBase { private readonly ILogger _logger; protected ServiceBase(ILogger logger) { _logger = logger; } protected void Log(string message) { _logger.Log(message); } } public class OrderService : ServiceBase { public OrderService(ILogger logger) : base(logger) { } }

This pattern keeps the dependency explicit. A derived class cannot accidentally forget to supply a logger because the compiler enforces the base constructor call.

You can also combine base parameters with derived-specific parameters:

public class PremiumOrderService : ServiceBase { public PremiumOrderService(ILogger logger, decimal discountRate) : base(logger) { DiscountRate = discountRate; } public decimal DiscountRate { get; } }

The base constructor handles the logger, while the derived constructor handles its own state.

Access Modifiers for Abstract Class Constructors

The access modifier on an abstract class constructor controls which derived classes can call it. protected is the most common choice because it allows any derived class to call the constructor while keeping it inaccessible from unrelated code.

public is allowed but rarely useful. Since you cannot instantiate an abstract class directly, a public constructor only matters when a derived class calls it. internal can be useful when you want to restrict construction to the same assembly, and private protected restricts it to derived classes within the same assembly.

Access modifierWho can call itTypical use
protectedAny derived classDefault for abstract class constructors
publicAny code, but only via a derived classRarely needed
internalAny class in the same assemblyFor framework or library code
private protectedDerived classes in the same assemblyWhen you need both constraints

Choose the most restrictive modifier that still allows the derived classes you intend to support. protected is usually sufficient.

Construction Order and Field Initialization

Understanding when the abstract class constructor runs is important for avoiding subtle bugs. In C#, when a derived instance is created, the derived class's instance field initializers run first, then the base class's field initializers, then the base constructor body, and finally the derived constructor body.

Consider this example:

public abstract class Base { protected Base() { Console.WriteLine("Base constructor"); } } public class Derived : Base { private readonly int _value = Initialize(); private static int Initialize() { Console.WriteLine("Derived field initializer"); return 42; } public Derived() { Console.WriteLine("Derived constructor"); } }

If you create a Derived instance, the output is:

Derived field initializer
Base constructor
Derived constructor

This order matters when a base constructor calls a virtual method. The derived field initializers have already run, so the virtual method sees the initialized fields. If you rely on the base constructor to set up state before the derived field initializers run, you will get unexpected behavior. Keep base constructors simple and avoid calling virtual methods from them.

Common Mistakes and Edge Cases

One common mistake is forgetting to call the base constructor when the abstract class only has a parameterized constructor. The compiler will report an error because there is no parameterless constructor to call.

Another mistake is making the abstract class constructor public and assuming it can be called directly. It cannot, and the public modifier gives no benefit over protected in most scenarios.

You also cannot mark an abstract class constructor as abstract or virtual. Constructors are not inherited in the polymorphic sense; each class must declare its own constructors, and the base constructor is invoked explicitly or implicitly.

If an abstract class has a static constructor, that runs once before any instance is created, but it is separate from instance construction. Static constructors are used to initialize static fields, not instance state.

Design Considerations for Shared Initialization

Use an abstract class constructor when you want to enforce that all derived classes provide certain inputs. This is a form of contract that the compiler enforces at construction time. It works well for required dependencies, configuration values, or resources that must be ready before any derived method runs.

Avoid putting heavy logic in the abstract class constructor. Constructors should be straightforward: assign fields, validate arguments, and maybe call a simple helper. If you need to perform asynchronous initialization or complex setup, consider a factory method or an async initialization pattern instead.

Also consider whether the base class should expose a parameterless constructor at all. If every derived class needs a connection string, forcing the parameterized constructor is better than allowing a default empty value. The compiler will then prevent derived classes from being created without that value.

When you design a class hierarchy, ask whether the shared state truly belongs in the base class. If only some derived classes need a particular field, placing it in the base constructor forces all derived classes to deal with it. In that case, a smaller base class or composition may be a better fit.

The c# abstract class constructor is a practical tool for shared initialization, but it should be used deliberately. Keep the constructor focused, choose an appropriate access modifier, and understand the construction order to avoid surprising runtime behavior.

c# abstract class constructor: Practical Usage and Code Exam | RYUSLOG DEV