delphi - how to pass a parameter from the instantiator to a constructor in the spring4d dependency injection framework?

和自甴很熟 提交于 2020-01-10 14:19:06

问题


It's possible to register a class with a parameter expected to be passed from the point of creation?

I know it can be done something like this:

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

But there the parameters are binded to the execution context where the container gets registered and not where the object get's intantiated.

Something like this it's possible for example?

GlobalContainer.Resolve<IMathService>([FCurrentUser]);

I know some peoble advocate to have very simple constructors, but there are times when a constructor parameter looks clearly the way to go:

  1. The object constructed needs the object parameter to work, so the reference must be satisfied. The parameter also makes that constraint much more obvious looking at the class.

  2. You can assign the reference in a method or property and raise and exception in every other method if you try to use the object without first making the assignment.. I don't like writing this type of code it's simply a waste of time, just use the constructor parameter and check there. Less code, the better IMO.

  3. Also the object being passed it's local to the object that constructs the new object using the container (for example a Transaction object) and has some state (it's not a new object that I can get with the container).


回答1:


I have added resolver overrides as in Unity.

So you can write:

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.

Edit 17.09.2018:

This changed quite some while ago and Resolve is accepting parameters via array of TValue. You can either pass values directly there which then have to match exactly the parameter list in the ctor. For only partially filling the parameters you can use TNamedValue or TTypedValue from Spring.pas

Anyway I suggest using factories to be injected and consumed by your code and not reaching into the container (global one or not) Resolve method.




回答2:


You could check out this thread: https://forums.embarcadero.com/message.jspa?messageID=440741

I've done an implementation on this in the framework and use it in my code. If you want it, I'll send it to you. Keep in mind that this is not how it might be done when and if they add functionality like this in the codebase. Baoquan has my code.

This implementation also handles if you try to resolve without all needed parameters, and gives you an exception showing the missing parameters.

You use it like this:

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

Value is stored as TValue and can be anything.

Registering the parameter with your class is done with attributes like this:

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

You can also do

[ContainerParameter]
FYourValue1:.. 

But then your parameter have 'FYourValue1' as name.



来源:https://stackoverflow.com/questions/9952353/delphi-how-to-pass-a-parameter-from-the-instantiator-to-a-constructor-in-the-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!