【问题标题】:How to inject field interface into an object如何将字段接口注入对象
【发布时间】:2015-05-20 09:26:27
【问题描述】:

我想给一个对象注入一个接口但是找不到属性[Inject]的问题

什么在起作用。

unit uStorage;

interface

uses
  uStorageInterface;

type
  TStorageService = class (TInterfacedObject, IStorageService)
  private
    FPath: String;
    procedure SetPath(const Value: String);
    function GetPath: String;
   public
     property Path: String read GetPath write SetPath;
   end;

implementation

{ TStorageService }

function TStorageService.GetPath: String;
begin
  Result:= FPath;
end;

procedure TStorageService.SetPath(const Value: String);
begin
  FPath := Value;
end;

unit uStorageInterface;

interface

type
   IStorageService = interface
     ['{F1B4C339-BE8E-4182-A191-95266160FA6E}']
     procedure SetPath(const Value: String);
     function GetPath: String;
     property Path: String read GetPath write SetPath;
   end;

   IStorageObject = interface
     ['{7B97B659-EDF3-4892-AFAB-985487660372}']
   end;

implementation

end.

unit uObjects;

interface

uses
  Vcl.StdCtrls,
  System.Classes,
  uStorageInterface,
  Spring.Container,
  Spring.Services,
  Spring.Container.Common;

type

  TMyButton= class (TButton, IStorageObject)
  private
    FStorage: IStorageService;
    function GetStorage: IStorageService;

  protected
    procedure DoExit; override;

  public
    constructor Create(AOwner: TComponent); override;
  end;

implementation

{ TMyButton }
constructor TMyButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FStorage:= ServiceLocator.GetService<IStorageService>;
end;

procedure TMyButton.DoExit;
begin
  inherited;
    if assigned(FStorage) then
  begin
    self.Caption:= FStorage.Path;
  end;
end;

function TMyButton.GetStorage: IStorageService;
begin
  Result:= FStorage;
end;

end.

unit Unit2;

interface

uses
  System.SysUtils, System.Classes,
  Vcl.Dialogs;

type
  TDataModule2 = class(TDataModule)
    procedure DataModuleCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  DataModule2: TDataModule2;

implementation

uses
  uStorage,
  uObjects,
  uStorageInterface,
  Spring.Services,
  Spring.Container;

{%CLASSGROUP 'Vcl.Controls.TControl'}

{$R *.dfm}

procedure TDataModule2.DataModuleCreate(Sender: TObject);
begin
  GlobalContainer.RegisterType<TStorageService>.Implements<IStorageService>.DelegateTo(
    function: TStorageService
    begin
      Result := TStorageService.Create();
      Result.Path:= 'MyButton';
    end).AsSingleton;
  GlobalContainer.Build;
end;
end.

在构造函数 TMyButton.Create(AOwner: TComponent) 中,我想用字段注入替换 ServiceLocator,但我找不到如何做到这一点。

一些例子,但它不起作用。我看不到问题。

unit uObjects;

interface

uses
  Vcl.StdCtrls,
  System.Classes,
  uStorageInterface,
  Spring.Container,
  Spring.Services,
  Spring.Container.Common;

type

  TMyButton= class (TButton, IStorageObject)
  private
    [Inject]
    FStorage: IStorageService;
    function GetStorage: IStorageService;

  protected
    procedure DoExit; override;

  public
    constructor Create(AOwner: TComponent); override;
  end;

implementation

{ TMyButton }
constructor TMyButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  //FStorage:= ServiceLocator.GetService<IStorageService>;
end;

procedure TMyButton.DoExit;
begin
  inherited;
    if assigned(FStorage) then
  begin
    self.Caption:= FStorage.Path;
  end;
end;

function TMyButton.GetStorage: IStorageService;
begin
  Result:= FStorage;
end;

end.

procedure TDataModule2.DataModuleCreate(Sender: TObject);
begin
  GlobalContainer.RegisterType<TStorageService>.Implements<IStorageService>.DelegateTo(
    function: TStorageService
    begin
      Result := TStorageService.Create();
      Result.Path:= 'MyButton';
    end).AsSingleton;

  GlobalContainer.RegisterType<TMyButton>.Implements<IStorageObject>.InjectField('FStorage');
  GlobalContainer.Build;
end;

当我在运行时创建 TMyButton 时,TMyButton 中的 FStorage 为零。 当我使用 FStorage:= ServiceLocator.GetService;然后在构造函数中分配 FStorage。但我想使用注入而不是 ServiceLocator。如果可以的话。

【问题讨论】:

  • 当我使用注入属性时,FStorage 为 nil

标签: delphi dependency-injection spring4d


【解决方案1】:

首先TMyButton的注册错误。容器本身不会为 Aowner 填充 nil。这意味着它将回退到 TObject 构造函数,使按钮实例半初始化。

要么使用子依赖解析器为 TComponent ctor 执行此操作,要么以这种方式显式注册它。

GlobalContainer.RegisterType<TMyButton>.Implements<IStorageObject>
  .DelegateTo(
    function: TMyButton
    begin
      Result := TMyButton.Create(nil);
    end)
  .InjectField('FStorage');

现在注意!如果您在某处将其解析为 TMyButton,则容器不知道如何解决该问题,因为您将 IStorageObject 指定为服务类型。如果您指定服务类型,除非明确定义,否则容器不会解析该类。 然而,这里有一个小故障,因为容器在解析该类时会尝试再次注册该类。这导致 TMyButton 的第二次注册没有指定字段注入。我会解决的。

在此之前,您可以通过在您的注册中添加 Implements&lt;TMyButton&gt; 来解决此问题。

【讨论】:

  • 我知道注册错了。是否有关于子依赖的链接。我只是一个初学者,有时很难理解这种方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-08
  • 2019-11-23
  • 1970-01-01
  • 2019-07-06
  • 1970-01-01
相关资源
最近更新 更多