views:

303

answers:

1

The documentation for Autofac has an interesting page describing its ability to automatically generate delegate factories. It also strongly suggests that you can get similar results without Autofac by writing them by hand.

I'm using Unity for IoC and would like to avoid passing the container around to objects that need to create other objects, so how would you write a delegate factory without Autofac?

+3  A: 

Hi. Well I've never used Unity so far, so my answer is quite vague.

The principal is simple. You define some delegates which represent factories. Then you create a ‘factory’-class which has public methods which matches the delegates. This class knows the container. Now you register the delegate and set that class as implementation. Then you can inject only the delegate. When you call the injected delegate, the factory-class is called, which knows the container and asks the container for a new instance.

First you define your factory-delegates.

public delegate TServiceType Provider<TServiceType>();
public delegate TServiceType Provider<TArg,TServiceType>(TArg argument);

The you create a generic factory:

/// <summary>
/// Represents a <see cref="Provider{TArg,TServiceType}"/> which holds 
/// the container context and resolves the service on the <see cref="Create"/>-call
/// </summary>
internal class GenericFactory{
    private readonly IContainer container; 

    public ClosureActivator(IContainer container)
    {
        this.container= container;
    } 

    /// <summary>
    ///  Represents <see cref="Provider{TServiceType}.Invoke"/>
    /// </summary>
    public TService Create()
    {
        return container.Resolve<TService>();
    }
    /// <summary>
    /// Represents <see cref="Provider{TArg,TServiceType}.Invoke"/>
    /// </summary>
    public TService Create(TArg arg)
    {        
        return container.Resolve<TService>(new[] {new TypedParameter(typeof (TArg),arg)});
    }
}

Now what you register the delegate, something like this:

var newServiceCreater = new GenericFactory(container);
container.Register<Provider<MyCompoent>>().To(newServiceCreater.Create);

var newServiceCreater = new GenericFactory(container);
container
    .Register<Provider<OtherServiceWithOneArgumentToConstruct>>()
    .To(newServiceCreater.Create);

Now other you inject to other components just the ‘Provider’ instead of the container.

Gamlor
That got me started - many thanks!
GraemeF