Home > front end >  In Spring4D how to ResolveAll IFactory, supplying an argument from the container?
In Spring4D how to ResolveAll IFactory, supplying an argument from the container?

Time:03-23

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
  • Related