2015-05-20 5 views
3

Я хочу, чтобы ввести интерфейс в объект, но я не могу найти проблему атрибута [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) Я хочу, чтобы заменить с поиска сервиса инъекции поля, но я не могу найти, как это сделать.

Некоторые примеры, но это не работает. Я не вижу проблемы.

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 во время выполнения, FStorage в TMyButton является Нилл. Когда я использую FStorage: = ServiceLocator.GetService; в конструкторе тогда назначается FStorage. Но я хочу использовать инъекцию, а не ServiceLocator. Если это возможно.

+0

FStorage - это нуль, когда я использую атрибут injection – Ravaut123

ответ

1

Первый Регистр TMyButton является неправильным. Контейнер не будет заполнять нить для AOwner сам по себе. Это означает, что он вернется к конструктору TObject, оставив экземпляр кнопки наполовину инициализированным.

Либо использовать преобразователь подзависимости для этого для TComponent ctors или явно зарегистрировать его таким образом.

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

Теперь внимание! Если вы разрешаете это как TMyButton где-то, контейнер не знает, как его решить, потому что вы указали IStorageObject как тип сервиса. Если вы укажете тип сервиса, контейнер не разрешит класс, если он явно не определен. Однако здесь есть небольшой сбой, так как контейнер пытается снова зарегистрировать этот класс всякий раз, когда он разрешается. Это приводит к второй регистрации для TMyButton, которая не имеет указанной инъекции поля. Я это исправлю.

До этого вы можете исправить это, добавив Implements<TMyButton> к вашей регистрации.

+0

Я знаю, что регистрация неверна. Есть ли ссылка о субзависимости. Я просто новичок, и мне иногда трудно понять этот метод. – Ravaut123

+0

Обновлен мой ответ –