I would like to call GlobalContainer.ResolveAll<IFactory<TBob,IItem>>
to return me an array of IFactories which when supplied with a TBob with return me an IItem.
I have the IItems registered as
GlobalContainer.RegisterType<IItem,TA>('A');
GlobalContainer.RegisterType<IItem,TB>('B');
But I can't find a way to register the individual IFactories such as
GlobalContainer.RegisterType<IFactory<TBob,IItem>('AFac',['A']);
GlobalContainer.RegisterType<IFactory<TBob,IItem>('BFac',['B']);
as there is not an option to specify the 'injected' values.
The only way I can find to do it is to have code like below for each factory but am sure there must be a cleaner way.
In the following code I have found I have to use TFunc and not IFactory as although they both are in fact TFunc I get an AV.
Also by doing this method I have to mark the constructor with [Inject] if there are any other parameters in the IItem's constructor otherwise the resolver picks the inherited constructor.
GlobalContainer.RegisterType<TFunc<TBob,IItem>>('AFac').DelegateTo(
function: TFunc<TBob,IItem>
begin
Result:=function(Bob: TBob): IItem
begin
Result:=GlobalContainer.Resolve<IItem>('A',[Bob]);
end;
end
);
CodePudding user response:
Factories are registered via RegisterFactory
and they only support interfaces with methodinfo ($M
or inherited from IInvokable
) or anonymous method type that have the methodinfo enabled such as Func<...>
(recommended) from Spring.pas (introduced in 2.0) (not TFunc<...>
from SysUtils.pas). That is because it uses the parameter info to dynamically build the factory code.
You did not explicitly stated that but I assume the constructors of TA
and TB
both look like this:
constructor Create(bob: TBob);
You then register them like this (keep in mind that this might not work when all code is in a simple test dpr because of some typeinfo glitches when they are inside the dpr) - the types being registered in the container need to be in a unit.
GlobalContainer.RegisterType<IItem, TA>('A');
GlobalContainer.RegisterType<IItem, TB>('B');
GlobalContainer.RegisterFactory<Func<TBob,IItem>>('AFactory', 'A', TParamResolution.ByType);
GlobalContainer.RegisterFactory<Func<TBob,IItem>>('BFactory', 'B', TParamResolution.ByType);
GlobalContainer.Build;
var factories := Globalcontainer.ResolveAll<Func<TBob,IItem>>;
for var factory in factories do
begin
var item := factory(nil);
Writeln((item as TObject).ClassName);
end;
This will print:
TA
TB