Set*_*384 3 delphi dependency-injection ioc-container spring4d
使用Spring4D时,如何在调用GlobalContainer时将字符串值作为参数传递.解析,以便在已解析的类构造函数上使用此字符串值?
我想解决映射到TWorker的类IWorker.TWorker类在它的构造函数中依赖于ITool加上工作者名称的字符串.
我猜的答案在于TValue数组,它可以作为GlobalContainer.Resolve的参数给出,但我不明白如何使用它.
我发现这篇文章关于在调用可能有效的GlobalContainer.Resolve时使用TParameterOverride作为参数,但这个功能似乎已经在Spring4D的1.1版本中消失了.
我想在注册我的类型时避免调用InjectConstructor.
我需要帮助的部分是
GlobalContainer.Resolve<IWorker>([{what do I put here?}]).Work;
Run Code Online (Sandbox Code Playgroud)
这是我的一个小项目
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Spring.Container;
type
IWorker = interface
['{2BBD7E9C-4806-4F01-9B05-9E9DD928D21D}']
procedure Work;
end;
ITool = interface
['{F962209D-4BC3-41C4-9089-0A874632ED1A}']
procedure Use;
end;
TWorker = class(TInterfacedObject, IWorker)
private
FTool: ITool;
FName: string;
procedure Work;
public
constructor Create(tool: ITool; name: string);
end;
THammer = class(TInterfacedObject, ITool)
private
procedure Use;
end;
{ TWorker }
constructor TWorker.Create(tool: ITool; name: string);
begin
FTool := tool;
FName := name;
end;
procedure TWorker.Work;
begin
Writeln(FName + ' is working');
FTool.Use;
end;
{ THammer }
procedure THammer.Use;
begin
Writeln('Using a hammer');
end;
begin
try
GlobalContainer.RegisterType<ITool, THammer>;
GlobalContainer.RegisterType<IWorker, TWorker>; // TWorker constructor = Create(tool: ITool; name: string);
GlobalContainer.Build;
GlobalContainer.Resolve<IWorker>([{what do I put here?}]).Work;
GlobalContainer.Resolve<IWorker>(['THammer.Create', 'Bob']).Work; //--> 'Unsatisfied constructor on type: TWorker'
GlobalContainer.Resolve<IWorker>([THammer.Create, 'Bob']).Work; //--> Access violation
GlobalContainer.Resolve<IWorker>([nil, 'Bob']).Work; //--> 'Unsatisfied constructor on type: TWorker'
Readln;
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
Readln;
end;
end;
end.
Run Code Online (Sandbox Code Playgroud)
帮助将不胜感激.谢谢!
正如Sam所说,你应该避免在整个代码中使用容器作为服务定位器,因为这只是对容器调用的构造函数调用的替代,这导致代码比硬连接的所有代码更糟糕.
虽然它是可能的参数传递给resolve调用它真的应该利用工厂来解决.
这将是如何为name参数传递一个值(该工具由容器注入,因为它知道它(TNamedValue在声明中Spring.pas).
GlobalContainer.Resolve<IWorker>([TNamedValue.Create('name', 'Bob')]).Work;
Run Code Online (Sandbox Code Playgroud)
但是我们可以将这些代码与注册工厂结合起来(遗憾的是因为RTTI缺少关于类型的信息,我们必须使用匿名方法类型TFunc<...>)
type
TWorkerFactory = TFunc<string, IWorker>;
...
GlobalContainer.RegisterType<ITool, THammer>;
GlobalContainer.RegisterType<IWorker, TWorker>;
GlobalContainer.RegisterInstance<TWorkerFactory>(
function (name: string): IWorker
begin
Result := GlobalContainer.Resolve<IWorker>([TNamedValue.Create('name', name)]);
end);
GlobalContainer.Build;
GlobalContainer.Resolve<TWorkerFactory>.Invoke('Bob').Work;
Run Code Online (Sandbox Code Playgroud)
因此,这使您可以TWorkerFactory在代码中的某处放置一个参数,然后容器可以注入它.这样你就可以使用依赖注入来解耦代码,但是没有任何直接依赖于容器(实际上你仍然可以手动连接所有内容,这是我之前所说的规则)
在1.2版本中,容器将支持自动工厂创建,因此您可以编写如下代码:
type
{$M+}
TWorkerFactory = reference to function(const name: string): IWorker;
...
GlobalContainer.RegisterFactory<TWorkerFactory>;
Run Code Online (Sandbox Code Playgroud)
这会自动创建一个代理,将工厂方法的参数进一步传递到容器中.