C# Programming Tutorial 0/45 lessons ~6 min read Lesson 15

    Constructors

    Constructors initialize object state at creation.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Constructors initialize object state at creation. C# supports instance constructors, static constructors, primary constructors, and constructor chaining with : this(...) or : base(...). DI containers call constructors to inject dependencies in ASP.NET Core services.

    Interviewers ask about constructor vs factory, static constructor thread safety, and record positional constructors. Avoid heavy work in constructors — prefer factory or async initialization patterns for I/O.

    This lesson covers every constructor form with enterprise service examples.

    The story

    An invoicing microservice needs the current UTC time from an injectable clock (so unit tests can freeze time) and optionally a default currency for international clients. Constructor chaining lets one constructor delegate to another, and dependency injection supplies the clock automatically in ASP.NET Core.

    Understanding the topic

    Key concepts

    • Constructor name matches class; no return type.
    • Default parameterless constructor auto-generated if no other defined.
    • this(...) chains to another constructor in same class.
    • base(...) chains to parent constructor.
    • Static constructor runs once before first static access.
    • Primary constructor (C# 12) declares parameters on class line.

    Step-by-step explanation

    1. new triggers allocation then constructor chain.
    2. Fields initialize in declaration order, then constructor body.
    3. Static constructor initializes static fields thread-safely once.
    4. DI resolves constructor with most parameters it can satisfy.
    5. Private constructor prevents external instantiation — singleton/factory.
    6. Records generate public positional constructor automatically.

    Practical code example

    Service with constructor injection and chained overload:

    csharp
    namespace TechLearningPro.Constructors;
    public interface IClock { DateTimeOffset UtcNow { get; } }
    public sealed class InvoiceService(IClock clock)
    {
    private readonly IClock _clock = clock;
    public InvoiceService(IClock clock, string defaultCurrency)
    : this(clock)
    {
    DefaultCurrency = defaultCurrency;
    }
    public string DefaultCurrency { get; } = "USD";
    public Invoice Create(string customerId, decimal amount) =>
    new(Guid.NewGuid().ToString("N"), customerId, amount, _clock.UtcNow);
    public sealed record Invoice(string Id, string CustomerId, decimal Amount, DateTimeOffset CreatedAt);
    }

    Line-by-line code explanation

    • public interface IClock abstracts time so tests can substitute a fake clock.
    • public sealed class InvoiceService(IClock clock) uses a primary constructor to capture the clock dependency.
    • private readonly IClock _clock = clock stores the injected clock in a readonly field.
    • public InvoiceService(IClock clock, string defaultCurrency) : this(clock) chains to the primary constructor.
    • : this(clock) runs the primary constructor logic before the secondary body executes.
    • DefaultCurrency = defaultCurrency sets the currency on the overload that accepts it.
    • public string DefaultCurrency { get; } = "USD" defaults to US dollars when not overridden.
    • Create(string customerId, decimal amount) builds a new invoice using the injected clock.
    • Guid.NewGuid().ToString("N") generates a compact unique invoice ID.
    • sealed record Invoice(...) is an immutable snapshot of the created invoice.

    Key takeaway: Primary constructor captures IClock. Secondary constructor chains with : this(clock). DI container uses public constructor with resolvable parameters.

    Real-world use

    Where you'll use this in production

    • ASP.NET Core services receiving ILogger, DbContext via constructor.
    • Immutable domain objects requiring all fields at creation.
    • EF Core entities with parameterless ctor for materialization.
    • Singleton with lazy static initialization.

    Best practices

    • Inject dependencies via constructor — explicit, testable.
    • Validate arguments in constructor; throw ArgumentNullException.
    • Keep constructors lightweight — no I/O or blocking.
    • Use factory methods when construction logic complex.
    • Provide parameterless private/protected ctor for serializers/EF.

    Common mistakes

    • Service locator inside constructor anti-pattern.
    • Calling virtual methods from constructor — fragile inheritance.
    • Forgetting to chain base(...) in derived class.
    • Two many constructor overloads — use options record.

    Advanced interview questions

    Q1BeginnerConstructor chaining this vs base?
    this calls sibling constructor; base calls parent constructor.
    Q2BeginnerWhen static constructor runs?
    Once before any static member access, thread-safe.
    Q3IntermediateWhy primary constructors?
    Reduce repetitive field assignment boilerplate in C# 12.
    Q4IntermediateConstructor injection benefits?
    Explicit dependencies, immutable fields, easy mocking in tests.
    Q5AdvancedEF Core requires parameterless constructor — reconcile with DI entity?
    Private parameterless for EF; public ctor with dependencies for domain factory; or use owned types/DTO projection.

    Summary

    Constructors initialize state; chain with this/base. Primary constructors and DI are modern enterprise defaults. Validate inputs; avoid heavy work in constructors. Static constructors run once for static initialization. Next: encapsulation and information hiding.

    Ready to mark this lesson complete?Track your journey across the entire course.