Delegate Factories

Factory adapters provide the instantiation features of the container to managed components without exposing the container itself to them.

If type T is registered with the container, Autofac will automatically resolve dependencies on Func<T> as factories that create T instances through the container.

Lifetime scopes are respected using delegate factories as well as when using Func<T> or the parameterized Func<X,Y,T> relationships. If you register an object as InstancePerDependency() and call the delegate factory multiple times, you’ll get a new instance each time. However, if you register an object as SingleInstance() and call the delegate factory to resolve the object more than once, you will get the same object instance every time regardless of the different parameters you pass in. Just passing different parameters will not break the respect for the lifetime scope.

Creation through Factories

Shareholdings

public class Shareholding
{
  public delegate Shareholding Factory(string symbol, uint holding);

  public Shareholding(string symbol, uint holding)
  {
    Symbol = symbol;
    Holding = holding;
  }

  public string Symbol { get; private set; }

  public uint Holding { get; set; }
}

The Shareholding class declares a constructor, but also provides a delegate type that can be used to create Shareholdings indirectly.

Autofac can make use of this to automatically generate a factory that can be accessed through the container:

var builder = new ContainerBuilder();
builder.RegisterType<Shareholding>();
var container = builder.Build();
var shareholdingFactory = container.Resolve<Shareholding.Factory>();
var shareholding = shareholdingFactory.Invoke("ABC", 1234);

The factory is a standard delegate that can be called with Invoke(), as above, or with the function syntax shareholdingFactory("ABC", 1234).

By default, Autofac matches the parameters of the delegate to the parameters of the constructor by name. If you use the generic Func types, Autofac will switch to matching parameters by type.

Portfolio

Other components can use the factory:

public class Portfolio
{
  Shareholding.Factory ShareholdingFactory { get; set; }
  IList<Shareholding> _holdings = new List<Shareholding>();

  public Portfolio(Shareholding.Factory shareholdingFactory)
  {
    ShareholdingFactory = shareholdingFactory;
  }

  public void Add(string symbol, uint holding)
  {
    _holdings.Add(ShareholdingFactory(symbol, holding));
  }
}

To wire this up, the Portfolio class would be registered with the container before building using:

builder.RegisterType<Portfolio>();

Using the Components

The components can be used by requesting an instance of Portfolio from the container:

var portfolio = container.Resolve<Portfolio>();
portfolio.Add("DEF", 4324);

Autofac supports the use of Func<T> delegates in addition to hand-coded delegates. Func<T> parameters are matched by type rather than by name.

The Payoff

Imagine a remote stock quoting service:

public interface IQuoteService
{
  decimal GetQuote(string symbol);
}

We can add a value member to the Shareholding class that makes use of the service:

public class Shareholding
{
  public delegate Shareholding Factory(string symbol, uint holding);

  IQuoteService QuoteService { get; set; }

  public Shareholding(string symbol, uint holding, IQuoteService quoteService)
  {
    QuoteService = quoteService;
    ...
  }

  public decimal Value
  {
    get
    {
      return QuoteService.GetQuote(Symbol) * Holding;
    }
  }

  // ...
}

An implementor of IQuoteService can be registered through the container:

builder.RegisterType<WebQuoteService>().As<IQuoteService>();

The Shareholding instances will now be wired up correctly, but note: the signature of Shareholding.Factory doesn’t change! Autofac will transparently add the extra parameter to the Shareholding constructor when a factory delegate is called.

This means that Portfolio can take advantage of the Shareholding.Value property without knowing that a quote service is involved at all.

public class Portfolio
{
  public decimal Value
  {
    get
    {
      return _holdings.Aggregate(0m, (a, e) => a + e.Value);
    }
  }

  // ...
}

Caveat

In a desktop (i.e. stateful) application, when using disposable components, make sure to create nested lifetime scopes for units of work, so that the nested scope can dispose the items created by the factories within it.