Delphi - 如何在Spring4D依赖注入框架中从实例化器传递参数到构造函数?

9

是否可以注册一个带有预期从创建点传递的参数的类?

我知道可以这样做:

GlobalContainer.RegisterType<TUserProcessor>.Implements<IUserUpgrader>.
AsTransient.DelegateTo(
    function: TUserProcessor
    begin
      Result := TUserProcessor.Create(GetCurrentUser);
    end
  );

但是在这种情况下,参数绑定到容器注册的执行上下文中,而不是对象实例化的上下文中。例如,是否可以做到这样?
GlobalContainer.Resolve<IMathService>([FCurrentUser]);

我知道有些人倡导使用非常简单的构造函数,但有时候构造参数看起来更明显方便:

  1. 所构造的对象需要对象参数才能工作,因此必须满足引用。参数也使得查看类时这个约束更加明显。

  2. 你可以在方法或属性中分配引用,并且如果在没有先进行赋值的情况下尝试使用对象,则在每个其他方法中引发异常。我不喜欢编写这种类型的代码,这只是浪费时间,只需使用构造函数参数并在那里检查即可。在我看来,代码越少越好。

  3. 传递的对象也是在使用容器(例如Transaction对象)构造新对象的对象本地化,并且具有一些状态(它不是可以通过容器获得的新对象)。


我不知道Spring4D中是否有一个重载的TContainer.Resolve<T>接受一个数组参数。我有所遗漏吗? - menjaraz
@menjaraz 这只是一个实现的想法(当然可以使用RTTI完成)。 - pragmatic_programmer
好的,那听起来像是一个功能请求。为什么不也将其发布到 spring4d Google Group 呢? - menjaraz
我知道的Stackoverflow用户中,Stefan GlienkeDaniele TetiNick Hodges都有关于[tag:spring4d]的实际经验。试着与他们联系一下,也许他们可以做出贡献。 - menjaraz
正如我在评论中回复你所报告的问题时所说,我个人认为将参数传递到Resolve方法中是不必要的。我同意Lasse V. Karlsen在这里写的内容:https://dev59.com/xHI_5IYBdhLWcg3wJPdu,但我也愿意讨论这个问题。 - Stefan Glienke
2个回答

7
我在Unity中添加了解析程序覆盖。因此,您可以编写以下内容:
program Demo;

{$APPTYPE CONSOLE}

uses
  Classes,
  Spring.Container,
  Spring.Container.Resolvers;

type
  IUserUpgrader = interface
    ['{ADC36759-6E40-417D-B6F7-5DCADF8B9C07}']
  end;

  TUser = class(TObject);

  TUserProcessor = class(TInterfacedObject, IUserUpgrader)
  public
    constructor Create(AUser: TUser);
  end;

constructor TUserProcessor.Create(AUser: TUser);
begin
  Writeln('called constructor with passed user');
end;

begin
  GlobalContainer.RegisterType<TUserProcessor>.Implements<IUserUpgrader>;
  GlobalContainer.Build;

  GlobalContainer.Resolve<IUserUpgrader>(
    TOrderedParametersOverride.Create([TUser.Create]));

  GlobalContainer.Resolve<IUserUpgrader>(
    TParameterOverride.Create('AUser', TUser.Create));

  Readln;
end.

编辑于2018年9月17日:

这已经改变了一段时间了,Resolve现在通过TValue数组接受参数。您可以直接传递值,这些值必须与构造函数中的参数列表完全匹配。如果只想部分填充参数,则可以使用Spring.pas中的TNamedValueTTypedValue

无论如何,我建议使用工厂来被你的代码注入和使用,而不是去调用容器(全局或非全局)的Resolve方法。


这似乎在当前版本中已经消失了(截至本帖发布时...)是这样吗? - Nick Hodges
感谢您的更新,Stefan。 - Nick Hodges

0

你可以查看这个帖子: https://forums.embarcadero.com/message.jspa?messageID=440741

我已经在框架中实现了这个功能,并在我的代码中使用它。如果你需要,我可以把它发送给你。请记住,当他们在代码库中添加这样的功能时,可能不是这样实现的。Baoquan 有我的代码。

这个实现还处理了如果你尝试解析没有所有必需参数的情况,并给出一个异常显示缺少的参数。

你可以像这样使用它:

ServiceLocator.GetService<ISomeObj>(ServiceParameters['paramname1',value1]['paramname2',value2]..);

值被存储为TValue并且可以是任何内容。

使用类似这样的属性将参数注册到您的类中:

private
  [ContainerParameter('paramname1')]
  FYourValue1: ...;
  [ContainerParameter('paramname2')]
  FYourValue2: ..;

你也可以这样做

[ContainerParameter]
FYourValue1:.. 

但是你的参数名称为'FYourValue1'。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接