What is a Dependency

A dependency is an object a class needs to do its job. When a class creates its own dependencies with new, it's wired to them for good, and hard to test.

Apprentice · C# · OOP · Updated

After this lesson you can

  • Identify a class's dependencies, and explain the problems of creating them inside the class

Key takeaways

  • A dependency is an object a class needs to do its job, such as the Clock that Greeter needs.
  • A class that creates its own dependencies with new is hard-wired to them: to change one, you have to change the class itself.
  • A Greeter that makes its own new Clock() can't be tested reliably, because its greeting depends on when the test runs.
  • Dependency injection hands a class its dependencies from outside, so whoever creates the class decides which ones it gets.

Classes rarely work alone. A ProductDao needs a connection string. A controller needs a DAO. An order needs its menu items. When a class needs another object to do its job, that object is a dependency: the class depends on it.

A greeter that depends on a clock

Here's a Greeter that says good morning or good afternoon, depending on the time. It gets the time from a Clock:

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

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

public class Greeter
{
    private readonly Clock clock = new Clock();

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

Clock is a dependency of Greeter. And Greeter creates its own: new Clock(), right there in the class.

The trouble with new inside a class

It works. But run it in the morning and it says Good morning; run it after lunch and it says Good afternoon. Now try to test it:

  • A test that expects Good morning, Ada! passes before noon and fails after. A test whose result depends on when you run it can't be trusted.
  • To test the afternoon greeting, you'd have to wait until the afternoon.
  • There's no way to hand Greeter a different clock, because it builds its own.

The same trouble shows up everywhere a class creates what it needs:

The class creates So it's stuck with And testing it means
new Clock() The real time Waiting for the right time of day
new ProductDao("Server=localhost;Database=Northwind;...") That database, on that server Having that database, with the right rows in it
new EmailSender() Sending real email Sending real email to someone, every test run

A class that creates its dependencies is hard-wired to them: to change one, you have to change the class itself.

The fix, in one sentence

Don't let the class create its dependencies. Hand them in from outside, so whoever creates the class decides which clock, which database, which email sender it gets. That's dependency injection, and the next lesson shows how.

Check yourself

1 question to try on the lesson page.

So what

Every new inside a class for something it depends on is a decision made too early. Spot those, and you've found the places where your code is hard to test and hard to change.

Key terms

Cheat sheets