# Constructor Injection

A class asks for its dependencies in its constructor and keeps them in readonly fields. Whoever creates it passes them in, so a test can pass a fake.

Journeyman · C# · OOP · Updated November 3, 2026

## After this lesson you can

- Inject a dependency through a constructor and keep it in a readonly field
- Pass a fake dependency in a test, so the result doesn't depend on the outside world

## Key takeaways

- With constructor injection, a class asks for its dependencies as constructor parameters instead of creating them with `new`.
- Keep an injected dependency in a `readonly` field, so it never changes once the constructor sets it.
- In a test, pass a fake such as `new FixedClock(9)`, so the result is the same at any time of day.
- `ProductDao` asking for its connection string is dependency injection too: the app or the test decides which database it uses.
- ASP.NET Core has a built-in container that creates controllers and passes in what their constructors ask for, such as `IConfiguration`.

**Dependency injection** means a class receives its dependencies instead of creating them. The most common way is through the **constructor**: the class asks for what it needs, as parameters, and keeps them.

## Asking for the clock

Here's the `Greeter` from the last lesson, rewritten to ask for its clock:

```csharp
Greeter greeter = new Greeter(new Clock());
Console.WriteLine(greeter.Greet("Ada"));

public class Clock
{
    public virtual int Hour => DateTime.Now.Hour;
}

public class Greeter
{
    private readonly Clock clock;

    public Greeter(Clock clock)
    {
        this.clock = clock;
    }

    public string Greet(string name)
    {
        return clock.Hour < 12 ? $"Good morning, {name}!" : $"Good afternoon, {name}!";
    }
}
```

Three small changes:

1. **The field has no `new`.** `Greeter` no longer decides which clock it gets.
2. **The constructor asks for a `Clock`** and keeps it in the field.
3. **The field is `readonly`:** once the constructor sets it, it never changes.

The code that creates the greeter, here `new Greeter(new Clock())`, now makes the decision.

## A fake clock for testing

Because `Hour` is `virtual`, a test can pass a **fake** clock that always says the same time. A fake is a stand-in that behaves predictably:

```csharp
Greeter morning = new Greeter(new FixedClock(9));
Greeter afternoon = new Greeter(new FixedClock(15));

Console.WriteLine(morning.Greet("Ada"));
Console.WriteLine(afternoon.Greet("Ada"));

public class Clock
{
    public virtual int Hour => DateTime.Now.Hour;
}

// A fake clock for tests: it's always the hour it was given.
public class FixedClock : Clock
{
    private readonly int hour;

    public FixedClock(int hour)
    {
        this.hour = hour;
    }

    public override int Hour => hour;
}

public class Greeter
{
    private readonly Clock clock;

    public Greeter(Clock clock)
    {
        this.clock = clock;
    }

    public string Greet(string name)
    {
        return clock.Hour < 12 ? $"Good morning, {name}!" : $"Good afternoon, {name}!";
    }
}
```

```text
Good morning, Ada!
Good afternoon, Ada!
```

Now both greetings can be tested at any time of day, and every run gives the same answer. That's polymorphism at work: `Greeter` holds a `Clock`, and the object behind it can be the real clock or a fixed one. (In *Abstraction and Interfaces*, you'll meet a cleaner way to define what a clock must do.)

A test looks like this:

```csharp
[TestMethod]
public void Greet_BeforeNoon_SaysGoodMorning()
{
    Greeter greeter = new Greeter(new FixedClock(9));

    string greeting = greeter.Greet("Ada");

    Assert.AreEqual("Good morning, Ada!", greeting);
}
```

## You've already used it

The connection string has been injected all along. `ProductDao` asks for it in its constructor:

```csharp
public ProductDao(string connectionString)
{
    this.connectionString = connectionString;
}
```

So the app decides which database the DAO uses, and the exercise's tests decided for themselves: they passed their own connection string, which could point at any database, without a change to the DAO. And in *ASP.NET Core MVC*, `ProductsController` asked for `IConfiguration` in its constructor, and ASP.NET Core passed it in. That's dependency injection too: ASP.NET Core has a built-in **container** that creates controllers and hands them what they ask for. *ASP.NET Core MVC in Depth* shows how to register your own classes with it.

## Check yourself

2 questions to try on the lesson page.

## So what

Ask, don't make: a class that asks for its dependencies in its constructor can be given the real ones in the app and fakes in the tests. That one habit makes code testable, and it's how every ASP.NET Core app is built.

## Key terms

- [Constructor Injection](https://www.ask-codey.com/glossary/constructor-injection-oop)
- [Dependency Injection](https://www.ask-codey.com/glossary/dependency-injection)
- [Test Double](https://www.ask-codey.com/glossary/test-double)
- [Stub and Fake](https://www.ask-codey.com/glossary/stub-and-fake)

## Cheat sheets

- [Constructor Injection](https://www.ask-codey.com/cheat-sheets/dependency-injection-constructor-injection-cheat-sheet)

Source: https://www.ask-codey.com/lessons/dependency-injection-constructor-injection
