在 Spring4D 中如何解析所有 IFactory,从容器中提供一个参数?
In Spring4D how to ResolveAll IFactory, supplying an argument from the container?
我想调用 GlobalContainer.ResolveAll<IFactory<TBob,IItem>>
来 return 我是一个 IFactories 数组,当它与一个 TBob 一起提供时 return 我是一个 IItem。
我已将 IItems 注册为
GlobalContainer.RegisterType<IItem,TA>('A');
GlobalContainer.RegisterType<IItem,TB>('B');
但我找不到注册单个 IFactories 的方法,例如
GlobalContainer.RegisterType<IFactory<TBob,IItem>('AFac',['A']);
GlobalContainer.RegisterType<IFactory<TBob,IItem>('BFac',['B']);
因为没有指定 'injected' 值的选项。
我能找到的唯一方法是为每个工厂使用如下代码,但我确信必须有更简洁的方法。
在下面的代码中我发现我必须使用 TFunc 而不是 IFactory 因为它们实际上都是 TFunc 我得到一个 AV.
此外,通过执行此方法,如果 IItem 的构造函数中有任何其他参数,我必须用 [Inject] 标记构造函数,否则解析器将选择继承的构造函数。
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
);
工厂是通过 RegisterFactory
注册的,它们只支持带有 methodinfo 的接口($M+
或从 IInvokable
继承)或启用了 methodinfo 的匿名方法类型,例如 Func<...>
(推荐)来自 Spring.pas(在 2.0 中引入)(不是来自 SysUtils.pas 的 TFunc<...>
)。那是因为它使用参数info来动态构建工厂代码。
你没有明确说明,但我假设 TA
和 TB
的构造函数看起来都是这样的:
constructor Create(bob: TBob);
然后你像这样注册它们(请记住,当所有代码都在一个简单的测试 dpr 中时,这可能不起作用,因为当它们在 dpr 中时会出现一些类型信息故障) - 在容器中注册的类型需要在一个单位。
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;
这将打印:
TA
TB
我想调用 GlobalContainer.ResolveAll<IFactory<TBob,IItem>>
来 return 我是一个 IFactories 数组,当它与一个 TBob 一起提供时 return 我是一个 IItem。
我已将 IItems 注册为
GlobalContainer.RegisterType<IItem,TA>('A');
GlobalContainer.RegisterType<IItem,TB>('B');
但我找不到注册单个 IFactories 的方法,例如
GlobalContainer.RegisterType<IFactory<TBob,IItem>('AFac',['A']);
GlobalContainer.RegisterType<IFactory<TBob,IItem>('BFac',['B']);
因为没有指定 'injected' 值的选项。
我能找到的唯一方法是为每个工厂使用如下代码,但我确信必须有更简洁的方法。
在下面的代码中我发现我必须使用 TFunc 而不是 IFactory 因为它们实际上都是 TFunc 我得到一个 AV.
此外,通过执行此方法,如果 IItem 的构造函数中有任何其他参数,我必须用 [Inject] 标记构造函数,否则解析器将选择继承的构造函数。
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
);
工厂是通过 RegisterFactory
注册的,它们只支持带有 methodinfo 的接口($M+
或从 IInvokable
继承)或启用了 methodinfo 的匿名方法类型,例如 Func<...>
(推荐)来自 Spring.pas(在 2.0 中引入)(不是来自 SysUtils.pas 的 TFunc<...>
)。那是因为它使用参数info来动态构建工厂代码。
你没有明确说明,但我假设 TA
和 TB
的构造函数看起来都是这样的:
constructor Create(bob: TBob);
然后你像这样注册它们(请记住,当所有代码都在一个简单的测试 dpr 中时,这可能不起作用,因为当它们在 dpr 中时会出现一些类型信息故障) - 在容器中注册的类型需要在一个单位。
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;
这将打印:
TA
TB