簡體   English   中英

在Spring4D中調用GlobalContainer.Resolve時,如何將字符串值作為參數傳遞?

[英]How can I pass a string value as a parameter when calling GlobalContainer.Resolve in 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;

這是我的一個小項目

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.

幫助將不勝感激。 謝謝!

正如Sam所說,你應該避免在整個代碼中使用容器作為服務定位器,因為這只是對容器調用的構造函數調用的替代,這導致代碼比硬連接的所有代碼更糟糕。

雖然可以將參數傳遞給決心調用它真的應該利用工廠來解決。

這將是如何傳遞name參數的值(該工具由容器注入,因為它知道它( TNamedValueSpring.pas聲明)。

GlobalContainer.Resolve<IWorker>([TNamedValue.Create('name', 'Bob')]).Work;

但是我們可以將這些代碼與注冊工廠結合起來(遺憾的是因為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;

因此,這使您可以在代碼中的某處放置TWorkerFactory參數,然后容器可以將其注入。 這樣你就可以使用依賴注入來解耦代碼,但是沒有任何直接依賴於容器(實際上你仍然可以手動連接所有內容,這是我之前所說的規則)

在1.2版本中,容器將支持自動工廠創建,因此您可以編寫如下代碼:

type
  {$M+}
  TWorkerFactory = reference to function(const name: string): IWorker;

...

GlobalContainer.RegisterFactory<TWorkerFactory>;

這會自動創建一個代理,將工廠方法的參數進一步傳遞到容器中。

通常的解決方案是在容器中為工人注冊工廠,然后要求工廠使用特定工具和字符串(名稱?)返回工人。

您當前的代碼看起來可能期望在應用程序中使用容器,這是一種氣味,因為容器應該只在Composition根中使用

我明白這應該避免,但我找到了一種方法來使用我的字符串參數調用resolve。

以下代碼有效,但不是一個好主意:

  GlobalContainer.RegisterType<ITool, THammer>;
  GlobalContainer.RegisterInstance<TFunc<string, IWorker>>(
     function(workerName: string): IWorker
     begin
           Result := TWorker.Create(GlobalContainer.Resolve<ITool>, workerName);
     end);
  GlobalContainer.Build;

  GlobalContainer.Resolve<TFunc<string, IWorker>>.Invoke('Bob').Work;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM