4

Я постараюсь ответить во второй раз. Не обвиняйте меня, пожалуйста.Как правильно ввести свойство в форму?

Ситуация:

У меня есть форма

TfrmMain = class(TForm) 
private 
    [Inject('IniFileSettings')] 
    FSettings: ISettings; 
public 
end; 

У меня есть процедура инициализации контейнера:

procedure BuildContainer(const container: TContainer); 
begin 
    container.RegisterType<TIniSettings>.Implements<ISettings>('IniFileSettings'); 

    container.RegisterType<TfrmMain, TfrmMain>.DelegateTo(
    function: TfrmMain 
    begin 
     Application.CreateForm(TfrmMain, Result); 
    end); 

    container.Build; 
end; 

Так что я инициализирует как TfrmMain, а также TIniSettings через контейнер.

в .dpr у меня есть:

begin 
    BuildContainer(GlobalContainer); 
    Application.Initialize; 
    Application.MainFormOnTaskbar := True; 
    Application.CreateForm(TfrmMain, frmMain); 
    Application.Run; 
end. 

Также у меня есть помощник для TApplication:

procedure TApplicationHelper.CreateForm(InstanceClass: TComponentClass; var Reference); 
var 
    locator: IServiceLocator; 
begin 
    locator := TServiceLocatorAdapter.Create(GlobalContainer); 
    if locator.HasService(InstanceClass.ClassInfo) then 
    TObject(Reference) := GlobalContainer.Resolve(InstanceClass.ClassInfo).AsObject 
    else 
    inherited CreateForm(InstanceClass, Reference); 
end; 

Проблема: когда я пытаюсь

procedure TfrmMain.FormCreate(Sender: TObject); 
begin 
    s := FSettings.ReadString('Connection', 'Server', 'localhost'); 
end; 

я получаю исключение AV потому что FSettings в настоящее время NIL.

Что такое правильный способ получить объект FSettings из контейнера?

UPDATE:

FSettings := GlobalContainer.Resolve<ISettings>; 

Эта строка работает отлично ... Как и в прошлый раз у меня есть проблемы в использовании [Inject] атрибут. Даже с решением от Стефана я могу сделать метод работы:

How to initialize main application form in Spring4D GlobalContainer?

+0

Почему вы чувствуете, что 'FSettings' должен быть отличным от' nil'? –

+0

@David выглядит так, как будто я применяю атрибут [Inject] для него ... Пожалуйста, посмотрите первый фрагмент кода в сообщении. Я делаю это неправильно? – mad

+0

Почему вы регистрируете свою основную форму в контейнере? Попытайтесь сделать одно за раз. Забудьте о своей форме и сосредоточьтесь на FSettings. Переместить вызов buildcontainer в событие FormCreate, тогда он работает? – whosrdaddy

ответ

6

Первая причина, почему контейнер не имеет HasService больше, потому что этот метод был удален. Вы можете получить к нему доступ следующим образом:

if container.Kernel.Registry.HasService(...) then // yeah yeah, I know LoD is crying right now ;) 

Я бы избегал смешивания с использованием ServiceLocator и GlobalContainer. Хотя они должны указывать на один и тот же экземпляр, это может быть не так, потому что на самом деле кто-то может указать один из них на другой экземпляр. Если вы действительно хотите использовать ServiceLocator в этом случае, то также разрешите с ServiceLocator. Но имейте в виду, что на нем ничего нет, что контейнер не знает (даже если вам нужно называть некоторые разные части ядра.

Но это не проблема, с которой вы сталкиваетесь здесь, когда вы вставляете настройки. проблема в том, что у вас есть время. Метод FormCreate (я просто догадываюсь, что он привязан к событию OnCreate). Таким образом, контейнер создает экземпляр TfrmMain, событие вызывается, а затем возвращается в код контейнера, который впоследствии выполняет все инъекции. то, что не было введено через конструктор в некотором коде, вызываемом во время построения, является временной связью.

Существуют различные подходы к этой проблеме:

  • переместив доступ к FSettings на какое-то событие, что получает срабатывает позже (как OnShow или OnActivate)
  • не используют инъекции поля может быть приятно но это связывает ваш код с контейнером, потому что «традиционный» код не может этого сделать. Используйте инъекцию свойств и сеттер, который выполняет код.

Когда вы рассматриваете инсталляцию конструктора, как для зависимостей, которые являются обязательными, и для инъекций свойств для тех, которые являются необязательными, я бы сказал, для ввода конструктора. Но зная, что вы работаете с потомком TComponent, я, вероятно, использовал бы инъекцию свойств в этом случае, хотя эта зависимость не является необязательной.

+0

Конструктор переопределения должен быть в порядке. Application.CreateForm по-прежнему вызывает виртуальный конструктор. AfterConstruction - еще один очевидный выбор. –

+0

Это не может работать вообще. Невозможно получить параметр через CreateForm. Я не читал достаточно внимательно. Вы можете полностью поцарапать эту пулю. Не нужно быть уверенным, работает ли оно или нет. Это не так. –

+1

@Stefan Большое спасибо! Вы спасли мое утро. Правильный ответ: Timing. Теперь я использую вложенные объекты в OnShow. Прекрасно работает для меня. – mad

 Смежные вопросы

  • Нет связанных вопросов^_^