Spring4D - 如何从带有TComponent参数的容器解析到汽车工厂

问题描述 投票:0回答:2

举个例子,我想解析一个传入 TComponent 和 TNotifyEvent 的类,如下所示,但调用的是 TObject 的基本构造函数,而不是 TMy 的构造函数。

GlobalContainer.RegisterType<TMy>;
GlobalContainer.RegisterFactory<Func<TComponent,TNotifyEvent,TMy>>(TParamResolution.ByType);
var F:=GlobalContainer.Resolve<Func<TComponent,TNotifyEvent,TMy>>;
F(Self,Self.OnActivate);

我可以通过编写一些非常丑陋的代码来解决这个问题,如下所示,但我认为这种解决方案很常见,我一定做错了什么。

    TOther = class
    end;
    
    TMy = class
    public
      constructor Create(C: TComponent; N: TNotifyEvent; O: TOther);
    end;
    
    procedure TForm2.Button1Click(Sender: TObject);
    begin
      GlobalContainer.RegisterType<TOther>;
      GlobalContainer.RegisterType<TMy>;
    
      GlobalContainer.RegisterType<Func<TComponent,TNotifyEvent,TMy>>(
        function: Func<TComponent,TNotifyEvent,TMy>
        begin
          Result:=Func<TComponent,TNotifyEvent,TMy>(
            function(O: TComponent; N: TNotifyEVent): TMy
            begin
              Result:=TMy.Create(O,N,GlobalContainer.Resolve<TOther>);
            end
          );
        end
      );
      GlobalContainer.Build;
      var F:=GlobalContainer.Resolve<Func<TComponent,TNotifyEvent,TMy>>;
      F(Self,Self.OnActivate);
    end;

constructor TMy.Create(C: TComponent; N: TNotifyEvent; O: TOther);
begin
  OutputDebugString('Resolved');
end;

提前感谢您的指点。

delphi dependency-injection spring4d
2个回答
0
投票

这应该在开发中最新提交之后可以工作。

问题是类型化参数解析绑定到参数类型而不是参数类型。在这种情况下,这会导致类型为

TForm2
的类型化值(取自传递的参数),该值与类型
TComponent
的构造函数的 C 参数的类型不匹配,因为该匹配检查类型标识而不是作业兼容性。

修复后类型化参数解析完全适用于工厂函数的参数类型,而不是可能(在对象的情况下)更窄的实际参数类型。

FWIW 供将来参考 - 手动注册工厂时,通常不需要使用

RegisterType
提供委托,但可以直接使用
RegisterInstance
(请记住
Spring.Func<...> has 
const` 参数),当它没有任何捕获状态:

GlobalContainer.RegisterInstance<Func<TComponent,TNotifyEvent,TMy>>(
  function(const O: TComponent; const N: TNotifyEVent): TMy
  begin
    // ....
  end);

编辑:我还添加了自动检测最佳参数分辨率默认值。当工厂类型是

Spring.Func<...>
时,它会自动使用
ByType
,因此可以在
RegisterFactory
调用中省略它。对于所有其他类型,它像以前一样使用
ByName
作为默认值。


0
投票

Nick Hodges 在他的依赖书中使用此示例来创建容器:

unit uRegistration;

interface

procedure RegisterClassesAndInterfaces;

implementation
uses
  Spring.Container
  , uOrderEntry
  , uOrderValidator
  , uOrderProcessor;

procedure RegisterClassesAndInterfaces(aContainer: TContainer);
begin
  aContainer.RegisterType<IOrderProcessor, TOrderProcessor>.AsSingleton;
  aContainer.RegisterType<IOrderValidator, TOrderValidator>.AsSingleton;
  aContainer.RegisterType<IOrderEntry, TOrderEntry>.AsSingleton;
  aContainer.Build;
end;

end.

然后在代码中就可以使用

procedure DoOrderProcessing(aContainer: TContainer);
var
   Order: TOrder;
   OrderProcessor: IOrderProcessor;
begin
   Order := TOrder.Create;
   try
     OrderProcessor := aContainer.Resolve<IOrderProcessor>;
     if OrderProcessor.ProcessOrder(Order) then
     begin
       WriteLn('Order successfully processed....');
     end;
   finally
     Order.Free;
   end;
end;

您可以在这里获取这本书: https://lp.embarcadero.com/DependencyInjection

© www.soinside.com 2019 - 2024. All rights reserved.