Sometimes it’s all too easy to bring in a lot of really wasteful dependencies when you only require one particular piece of functionality that it provides. Other times it’s very easy to couple your codebase to littered calls to static members (and static calls aren’t a bad thing! But depending on the likes of your design philosophies / testing strategies, a codebase full of calls to DateTime.UtcNow is not necessarily a fun one to work with).

A technique I picked up a few years ago and have loved since is to depend on just a function, especially when using dependency injection to provide that. I see some amount of people recommending this in the .NET space but feel it’s not nearly widespread enough even as a concept people know you can do (choosing not to do it is a whole other thing).

I’ll stick with the likes of DateTime.Now for this example but here’s some other times I’ve found it appropriate:

  • To stop people introducing a local interface and a wrapper class to cover a call to a framework class. I am specifically calling out IDateTime and DateTimeWrapper here, and while I’m at it, do not put the word Wrapper in your interface name or I will come to your house and mess up your kitchen.
  • To give a class a means of creating objects and controlling their lifetime without creating a factory class.
  • When you want to design skinnier classes focused on functionality over knowing the roles of other classes.
  • Designing a method which depends on some functionality to be provided to it just for that one method.

An example

Let’s have a class with two static dependencies:

public class TimeLogger
{
    public void LogNow()
    {
        Console.WriteLine($"The time is {DateTime.Now}!");
    }
}

This is an absolute black box externally. It only supports default construction and the LogNow() method has no parameters or returns, this is the sort of code people love to talk about when striking fear into the hearts of people who have never needed to swap out an implementation, or provide a different one under different constructions for utility or whatever. And in spite of all this it provides value! I ran new TimeLogger().LogNow() just now and the program output The time is 02/12/2022 07:47:08!. That’s really useful to know, someone should patent that.

And what might be a very typical refactor to people striving to “Unit Test Everything” would be…

public TimeLogger(IConsole console, IDateTime dateTime)
{
    this.console = console;
    this.dateTime = dateTime;
}

public void LogNow()
{
    this.console.WriteLine($"The time is {this.dateTime.Now}!");
}

But this introduces terrible amounts of code bloat in my experience (two interfaces and two wrappers if that’s how you do these things). If you want to skew like me, towards the side of injecting capabilities over structures, we can change that to…

public TimeLogger(Action<string> log, Func<DateTime> now)
{
    this.log = log;
    this.now = now;
}

public void LogNow()
{
    this.log($"The time is {this.now()}!");
}

We no longer care that we’re logging to console, or how we’re sourcing the current time, we have merely expressed to our composer that we require some functionality to be provided to us and we’ll take care of the rest. This allows the class to focus on what it does and the composition can focus on the desired nuance. Here’s how that would look, composed and used:

static void Main(string[] args)
{
    var consoleTimeLogger = new TimeLogger(Console.WriteLine, () => DateTime.Now);
    consoleTimeLogger.LogNow();
}

Neat!

On Composition

I’ve seen others express this pattern before and it usually gets met with resistance by people who are mistaken on a couple things, so here’s some facts:

  • This is dependency injection.
  • Dependency injection is a separate concept to IoC containers.
  • Nothing here remotely prevents the use of IoC containers anyway.

In the example above I expressed how to compose this with pure DI, but for those of you using some kind of IoC container to hide the word new there’s a few ways you can go about hooking this up (I’ll use the ServiceCollection here). Firstly, let’s go about the horrible and wrong way to do this:

services.AddSingleton<Action<string>>(Console.WriteLine);
services.AddSingleton<Func<DateTime>>(() => DateTime.Now);
services.AddTransient<TimeLogger>();

Well it works and might cause you no problems in a tiny application that doesn’t change much but it’s simply horrid, we’re registering some pretty abstract stuff at the root of our application. What if another class wants to depend on DateTime.UtcNow? That’s the exact same type, you can’t register it the same. You can go sometimes down the path of trying to lean into tagging your dependencies with attributes to specify which Func<DateTime> you want, but that’s a bad pattern that makes your classes too dependency-aware, the opposite of good DI in my opinion.

Times like this I think it’s clearer to just express the implementation at the point of composition:

services.AddTransient(_ => new TimeLogger(Console.WriteLine, () => DateTime.Now));

Unless you have dependency hell, this isn’t too unmanageable and it ties some pretty abstract bits together in a crisp and clear way.

Once more, with purpose

Another route you can go down does introduce a smidge more clutter but it can be a really effective way to tie some static purpose to your dependencies using a keyword I often don’t see that much any more: delegate! Using delegates, we can type our functions like this:

public delegate void Log(string msg);
public delegate DateTime Now();

We can depend on concepts now, which have purpose defined statically:

public class TimeLogger
{
    private Log log;
    private Now now;
    
    public TimeLogger(Log log, Now now)
    {
        this.log = log;
        this.now = now;
    }
    
    public void LogNow()
    {
        this.log($"The time is {this.now()}!");
    }
}

And we can register functionality to fulfill this purpose:

services.AddSingleton<Log>(Console.WriteLine);
services.AddSingleton<Now>(() => DateTime.Now);
services.AddTransient<TimeLogger>();

This is great, this keeps the door open for defining a UtcNow in the same way and having other classes depend on that if you want. Now let’s get super silly with what else we can do…

public delegate void OutputNow();

services.AddTransient<OutputNow>(s => s.GetService<TimeLogger>().LogNow);

Now I can depend on the ability to output the current time rather than knowing what a TimeLogger is. I would not recommend doing this silliness with wild abandon, there’s a time and a place for it but I just wanted to demonstrate how you can start to define capabilities as dependencies throughout your application regardless of the implementation and still have it be IoC container friendly.

Hopefully these examples help inform the utility and execution of this really powerful pattern. I’ve found it saves on junk when wrapping system calls which you want to isolate from your tests, and provides a really neat way to inject simple factories such as delegate HttpClient MakeClient(HttpMessageHandler handler). HttpClient is a poor example for what I’m about to hammer home but nonetheless: this provides an excellent pattern for delegating the lifetime of a dependency to the dependent unit rather than riskily disposing something instantiated externally where such need to control the lifetime makes sense.

Now go and delete your interfaces!