I'm not sure whether SO is the correct place to ask the question, but existing SO questions don't help much(such as Autofac and Func factories), nor does Autofac document help, and google searching autofac factory func
couldn't get the answer either. I have basic knowledge of DI and IoC.
The primary goal was trying to understand a ~1k stared github repo ReactiveTrader, which demonstrates using reactive extension in real world application. I've successfully built(though took some effort) and ran both the server and client. and it is really excellent learning material!
While reading the code, I was stucked by several constructors injection like this:
public SpotTilesViewModel(IReactiveTrader reactiveTrader,
Func<ICurrencyPair, SpotTileSubscriptionMode, ISpotTileViewModel> spotTileFactory,
IConcurrencyService concurrencyService,
ILoggerFactory loggerFactory)
There's a Func<TSource1, TSource2, TTarget>
called somefactory in the constructor, there's no explicit reference to the constructor(so it must be DI right?), and there's no code registering the Func type(which is used in above SO answer I mentioned):
builder.RegisterType<Func...
So I'm very curious about why such Func<>
factory in constructor is useful, and how does it work, and if possible, could you give a simplest demo? Many thanks!
I'm neither familiar with that particular feature of Autofac nor the code base to which you refer, but some DI Containers support automatic generation of functions. After all, a function (or delegate) is just an anonymous interface; it's another way to model polymorphism.
A delegate with the type Func<ICurrencyPair, SpotTileSubscriptionMode, ISpotTileViewModel>
is a function that will return an ISpotTileViewModel
object if you supply an ICurrencyPair
and a SpotTileSubscriptionMode
. That's isomorphic to an interface like this:
public interface ISpotTileViewModelFactory
{
ISpotTileViewModel Create(ICurrencyPair pair, SpotTileSubscriptionMode mode);
}
Some DI Containers can autogenerate such factory interfaces as well. The algorithm goes something like this:
Keep in mind that at the heart of a DI Container is a table of mappings from polymorphic types to concrete types. For instance, the interface ISpotTileViewModel
is mapped to a concrete type. Skimming the GitHub repository for the code base in question, I guess that the SpotTileViewModel
class is the concrete type paired with ISpotTileViewModel
.
The SpotTileViewModel
class has one constructor. Thus, in order to be able to create an instance of it, the DI Container must analyse the constructor to figure out how to invoke it. It looks like this:
public SpotTileViewModel(
ICurrencyPair currencyPair,
SpotTileSubscriptionMode spotTileSubscriptionMode,
Func<ICurrencyPair, SpotTileSubscriptionMode, ISpotTileViewModel, ISpotTilePricingViewModel> pricingFactory,
Func<ITrade, ISpotTileViewModel, ISpotTileAffirmationViewModel> affirmationFactory,
Func<string, ISpotTileViewModel, ISpotTileErrorViewModel> errorFactory,
Func<ISpotTileConfigViewModel> configFactory)
It looks like a bit of a mouthful, but there's the ICurrencyPair
and SpotTileSubscriptionMode
, as well as four other functions.
The DI Container must now figure out how it can (if possible) create each of those six constructor arguments. It proceeds recursively through its table of mappings until it figures it out or has to give up. This process is what Steven van Deursen and I call Auto-Wiring in DIPPP.
My guess is that the DI Container has mappings for most of the polymorphic types in play here: ISpotTileAffirmationViewModel
, ISpotTileErrorViewModel
, and so on. Possible exceptions (but I'm speculating here) are exactly ICurrencyPair
and SpotTileSubscriptionMode
. But then, if you supply those two missing pieces, the DI Container knows how to map all the other pieces of the puzzle, and via Reflection Emit, it's able to 'code at run time' a function with the type Func<ICurrencyPair, SpotTileSubscriptionMode, ISpotTileViewModel>
.