Lazy Resolution with Func<TService>

Feb 12, 2009 at 8:35 PM
Kzu,

In some of my classes I like to delay the loading of dependencies for as long as possible, and I do this by accepting a Func<TService> as a ctor parameter rather than an instance of TService.

I was wondering whether it would be possible to add the ability to resolve a Func<TService> from a container even when I've only registered TService. Since you know how to instantiate TService, if I ask for a Func<TService> then you should be able to hand me a function that wraps up the Func<Container, TService> I've already given you, automatically passing in "this" as the parameter.

Then this sort of thing would be possible:

interface IBar { ... }
class Foo
{
    public Foo(Func<IBar> barFactory) { ... }
}

builder.Register<IBar>(c => new Bar());
builder.Register<IFoo>(c => new Foo(c.Resolve<Func<IBar>>()));

The container would resolve Func<IBar> by returning a function that resolves IBar, passing itself into "c".

Does that make sense? I really think that would be a killer feature. I don't know if other IoC containers do this.

Matt
Coordinator
Feb 26, 2009 at 5:55 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Jul 24, 2009 at 3:39 AM
Edited Jul 24, 2009 at 3:40 AM

Ok, so I feel a bit silly posting this after all this time, but I just had a flash of insight.

If I have a method like this:

public void DoStuff(Func<Foo> fooFactory)
{
    fooFactory();
}

... then right now I can call it like this:

DoStuff(container.LazyResolve<Foo>());

However, it has just occurred to me that I can also call it like this:

DoStuff(container.Resolve<Foo>);

Container.Resolve<Foo> is just a Func that returns a Foo, so I can pass that directly without having to call LazyResolve<Foo>. It also works if the function requires parameters - you just pass container.Resolve<Foo, Bar, int, string> or whatever.

Do we need LazyResolve? Do you think the former is more readable, or could we ditch LazyResolve and just pass the Resolve method pointer around like that?

Matt

Coordinator
Jul 24, 2009 at 12:09 PM

Good point Matt.

I'd still keep LazyResolve as it makes it more explicit. Passing the reference to Resolve is not evident enough I think (I missed that one too :)).

Jul 24, 2009 at 12:21 PM

Yeah I do agree that LazyResolve is more explicit and easier to understand.

I also wonder whether there's a (very small) performance gain by using LazyResolve. If I pass LazyResolve<Foo>() to a method, I'm passing the actual function that I used to register Foo with. If I pass Resolve<Foo> then I'm passing a pointer to a method which can "find" that function. Am I right? It's like LazyResolve is "one level lower" than the alternative.