Nano Hash - криптовалюты, майнинг, программирование

Как правильно внедрить свойство в форму?

Подниму вопрос во второй раз. Не вините меня, пожалуйста.

Ситуация:

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

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 из контейнера?

ОБНОВЛЕНИЕ:

FSettings := GlobalContainer.Resolve<ISettings>;

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

Как инициализировать основную форму приложения в Spring4D GlobalContainer?


  • Почему вы считаете, что FSettings должно отличаться от nil? 23.10.2014
  • @David выглядит так, как будто я применяю к нему атрибут [Inject] ... Пожалуйста, посмотрите на первый фрагмент кода в сообщении. Я делаю это неправильно? 23.10.2014
  • почему вы регистрируете свою основную форму в контейнере? Старайтесь делать одно дело за раз. Забудьте о своей форме и сосредоточьтесь на FSettings. Переместите вызов buildcontainer в событие FormCreate, тогда это работает? 23.10.2014
  • Я не вижу определения Inject. Это часть весны? В таком случае, я думаю, я отступлю от Q, будучи не в своей тарелке. 23.10.2014
  • @ Дэвид, да, это часть Spring4D Framework ... В любом случае спасибо 23.10.2014
  • @whosrdaddy Вот почему: stackoverflow.com/questions/24284401/ 23.10.2014
  • Ваш TApplicationHelper чем-то отличается от решения, предоставленного Стефаном Глиенке. 24.10.2014
  • Вот почему у GlobalContainer нет метода HasService(). Но в примере со Стефаном это... 24.10.2014
  • моя версия имеет это через TServiceLocatorAdapter... или через ServiceLocator.HasService 24.10.2014
  • Моя версия 1.1 (2014-09-12) 24.10.2014
  • Извините, мои глаза просто шутили, вы правы 24.10.2014
  • С прошлой попытки у меня не было времени попробовать подход Стефана... Теперь у меня есть немного времени, чтобы заставить Spring4D жить в моем проекте, но у меня те же трудности. 24.10.2014
  • Старый вопрос, но у меня была похожая проблема, и я столкнулся с ней. В моем случае я не использовал единицу измерения Spring.Container.Common, из-за чего атрибут [Inject] не распознавался. Однако компилятор дает хорошее предупреждение об этом, но если, как и я, вы погуглите, прежде чем читать подсказки компилятора, вы также можете оказаться здесь. ;-) 30.12.2019

Ответы:


1

Во-первых, причина, по которой в контейнере больше нет 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, я, вероятно, в этом случае использовал бы внедрение свойства, хотя эта зависимость не является обязательной.

23.10.2014
  • Конструктор переопределения должен быть в порядке. Application.CreateForm по-прежнему вызывает виртуальный конструктор. AfterConstruction — еще один очевидный выбор. 24.10.2014
  • Это вообще не может работать. Невозможно получить параметр через CreateForm. Я недостаточно внимательно читал. Вы можете полностью вычеркнуть этот пункт. Не нужно быть уверенным в том, работает он или нет. Это не так. 24.10.2014
  • @Стефан Большое спасибо! Вы спасли мое утро. Правильный ответ: время. Теперь я использую инъекционные объекты в OnShow. У меня работает нормально. 24.10.2014
  • CreateForm — единственный способ сделать основную форму 24.10.2014
  • Новые материалы

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

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..