|
DelegateFactories
Let components create instances of other components without hand-coding factories.
IntroductionRequirements in Autofac 1.3: Autofac.dll, using namespace Autofac.Builder; Requirements in Autofac 1.2: Autofac.Extras.GeneratedFactories.dll, using namespace Autofac.Extras.GeneratedFactories; Generated factories provide the component creation services of the container to managed components without exposing the container itself to them. Creation through FactoriesShareholdingspublic 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.Register<Shareholding>().FactoryScoped()
builder.RegisterGeneratedFactory<Shareholding.Factory>(new TypedService(typeof(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", 123). Autofac matches the parameters of the delegate to the parameters of the constructor by name. PortfolioOther 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.Register<Portfolio>(); Using the ComponentsThe components can be used by requesting an instance of Portfolio from the container: var portfolio = container.Resolve<Portfolio>();
portfolio.Add("DEF", 4324);Autofac 1.3 and later supports the use of Func<,...> delegates in addition to hand-coded delegates. Func parameters are matched by type rather than by name. The PayoffThe 'payoff' comes when we add real-world features to our application. Let's 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.Register<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);
}
}
...Differences with the Hand Coded ApproachIt is true that very similar results can be obtained by providing a hand-coded implementation of Shareholding.Factory. This is entirely possible and can be used alongside the 'automatic factories' if it becomes necessary. The advantages that come with the Autofac method are:
CaveatIn a desktop (i.e. stateful) application, when using disposable components, make sure to create nested containers for units of work, so that the nested container can dispose the items created by the factories within it. |
Sign in to add a comment