I’m reading a lot of blogs about development and .Net. One of the blogs I read is from Jimmy Bogard and one of the recent posts there is about guidelines for using Dependency Injection container.

I got involved in comments and one of the commenters was suggesting using Func<IFoo> as injection instead of injecting the instance for IFoo. And reasons for that were:

  1. The “captive dependency” problem… objects with more constrained lifetime being held by objects with longer->lived lifetime.

  2. The (wasteful) big-bang object graph problem… when an MVC action only requires 1 dependency, but the dependency graph for all dependencies within the controller need to be resolved.

  3. The occasional property injection… when its 2am and I don’t feel like fixing a circular dependency issue (don’t hate).

And a follow up comment:

If you have circular dependencies, you aren’t immediately evaluating the circular path

I’d like to address this first, as it bothers me very much myself. It is best recommended to avoid circular dependency and it is entirely possible (I have not yet came across the situation where code could not be refactored out of that). In classical DI you’d fix circular dependency with property injection. Let’s try to fix this problem with injection of a function.

Here is a simple situation with classes:

public interface IBar
{
    void DoBar();
}

public class Bar : IBar
{
    private readonly Func<IFoo> fooFunc;

    public Bar(Func<IFoo> fooFunc)
    {
        this.fooFunc = fooFunc;
    }


    public void DoBar()
    {
        var foo = fooFunc.Invoke();
        foo.DoFoo();

        Thread.Sleep(1000);
        Console.WriteLine("Executing Bar.DoBar");
    }
}

And Foo class:

public interface IFoo
{
    void DoFoo();
}

public class Foo : IFoo
{
    private readonly Func<IBar> barFunc;

    public Foo(Func<IBar> barFunc)
    {
        this.barFunc = barFunc;
    }


    public void DoFoo()
    {
        var bar = barFunc.Invoke();
        bar.DoBar();

        Thread.Sleep(1000);
        Console.WriteLine("Executing Foo.DoFoo");
    }
}

Foo depends on IBar and Bar depends on IFoo. Simple circular dependency with proposed injection of functions that resolve actual class entities.

Let’s see how we can create instance of Foo and instance of Bar

Func<IBar> barFunc = () => new Bar(???);

Func<IFoo> fooFunc = () => new Foo(barFunc);

We still have circular dependency, because we can’t create a function to resolve IBar without function that resolves IFoo first.

Ok, so no what? Let’s try to have one of the objects depend on function and another on an interface:

public class Bar : IBar
{
    private readonly IFoo foo;

    public Bar(IFoo foo)
    {
        this.foo = foo;
    }


    public void DoBar()
    {
        foo.DoFoo();

        Thread.Sleep(1000);
        Console.WriteLine("Executing Bar.DoBar");
    }
}

And Foo class is unchanged. And try to resolve both of the objects:

Func<IBar> barFunc = () => new Bar(new Foo(???));

Func<IFoo> fooFunc = () => new Foo(barFunc);

We still are in the same situation. We can’t resolve new instance of Bar because we can’t have Foo.

Another attempt – let’s do property injection:

public class Bar : IBar
{
    public Func<IFoo> FooFunc { get; set; }

    public Bar()
    {
    }

    public void DoBar()
    {
        var foo = FooFunc.Invoke();
        foo.DoFoo();

        Thread.Sleep(1000);
        Console.WriteLine("Executing Bar.DoBar");
    }
}

Now we are talking:

Func<IBar> barFunc = () => new Bar();

Func<IFoo> fooFunc = () => new Foo(barFunc);

var foo = fooFunc.Invoke();
var bar = new Bar()
                {
                    FooFunc = fooFunc,
                };

bar.DoBar();

The only problem that we still have circular dependency, only run-time, rather than compile time. See if you can figure out why it happens (just try running the code)! I’ve created a gist with full code I’ve tried running. Functions are unwrapped from lambdas, so you can set breakpoints and step into them while debugging.


Now, see if you notice a great big deception I’ve given you here. The dependency is very circular on functional level: DoBar() calls DoFoo() calls DoBar() calls DoFoo(), etc. It is impossible to run these functions: it is an infinite recursion/loop/whatever. And not type of wiring up will help you out. You’ll need to remove one of the function invocations from the classes:

public void DoFoo()
{
    Thread.Sleep(1000);
    Console.WriteLine("Executing Foo.DoFoo");
}

Now you can run the sample and it won’t explode with a series of exceptions. But our object wiring looks complex and is not much different from direct injection coupled with property injection of an object:

public class Bar : IBar
{
    public IFoo Foo { get; set; }

    public Bar()
    {
    }

    public void DoBar()
    {
        if (Foo == null)
        {
            throw new Exception("Foo property is not populated");
        }

        Foo.DoFoo();

        Console.WriteLine("Executing Foo.DoFoo");
    }
}


public class Foo : IFoo
{
    private readonly IBar bar;

    public Foo(IBar bar)
    {
        this.bar = bar;
    }

    public void DoFoo()
    {
        Thread.Sleep(1000);
        Console.WriteLine("Executing Foo.DoFoo");
    }
}

Wiring up and execution looks like this:

var bar = new Bar();
var foo = new Foo(bar);
bar.Foo = foo;

foo.DoFoo();
bar.DoBar();

The second version looks much more simple than the version with functions

Containers and function injection

In the same discussion I said that containers are not geared toward injection of functions. Well, yes, you can totally do this (Autofac):

var builder = new ContainerBuilder();
Func<IBar> barFunc = () => new Bar();

builder.RegisterInstance(barFunc);
builder.RegisterType<Foo>().As<IFoo>();
var container = builder.Build();

var foo = container.Resolve<IFoo>();
foo.DoFoo();

And it will work (given that Foo constructor takes Func<IBar>). But with given registration you can’t resolve Bar because it is not registered – we only registered Func<IBar>, but not IBar.

And I’m not aware of the way to register Func<IBar> together with IBar in one go, making it double-effort. Also imagine I have hundreds on ICommandHandler<TCommand> classes and hundreds of IQueryHandler<TQuery, TResult>. How can you register that with functions? Add a few decorators on top of that.

Probably one can come up with clever methods to do it, but that’ll be an addition to containers, not built-in functionality. And this is what I called “containers are not geared towards”.

Conclusion

However interesting this idea might seem like, I’ll stick to the classical DI with classes depending on interfaces. And all the issues discussed can be avoided by mostly following SOLID principles; no circular dependency; no massive graphs of objects; object resolution should be cheap and simple. To avoid captive dependency use Decoraptors.

  • P

    Hey Max – thanks for the post.

    I know I said this on Jimmy’s blog, but I’ll mention it here to be clear: I’m not suggesting that Func’ional injection is a better path than traditional injection. I’m soliciting feedback to understand where it will not work. Your blog post seems to be disputing whether or not Func’ional injection is better than traditional injection – I’m not asking if its better or worse (it’s probably a matter of taste). I’m very interested if you can come up with a scenario where Func’ional injection creates problems besides code smell.

    Let me help you with an example:

    > If you use Func’ional injection with Windsor, do you break the lifetime-management semantics that it offers? .. i.e., does Windsor no longer know when objects are being referenced within a dependency graph?

    > How is IDisposable handled with Func’ional injection?

    Hopefully my line of questioning is more clear now. Its less about “X is better than Y” … “Circular dependencies are bad!!” .. Its more about, “Why is Func’ional injection problematic?”

    Regarding containers not having native behavior, I’ve created a gist that uses Unity: https://gist.github.com/anonymous/56380a67eee7fb29bc38

    You can see that no special code is required to wire-up functional injection; it works out-of-the-box as expected.