Сначала был один контейнер, настроенный для размещения одного экземпляра (AsSingleton
) в качестве корня композиции. Затем эта настройка была перемещена в другой контейнер, чтобы разрешить из него несколько таких одноэлементных контейнеров, которые будут использоваться новым корнем композиции. Кроме того, корень композиции одноэлементных контейнеров использует атрибут Inject
метода. Теперь и внутренний одноэлементный контейнер, и внешний контейнер обрабатывают атрибут Inject
. Однако это требуется только для внутреннего контейнера-одиночки, который отвечает за создание экземпляра, а не для внешнего контейнера, который связывает только время жизни контейнера-одиночки с разрешенным экземпляром.
Как заставить (внешний) контейнер игнорировать атрибут Inject
для определенного типа?
(упрощенный) пример :
unit Example;
interface
uses
Spring.Container,
Spring.Container.Common;
type
TComponentB = class
end;
TComponentA = class // a TForm descendant
[Inject]
procedure Init(const ComponentB: TComponentB);
end;
procedure Register(const Container: TContainer);
procedure Run;
implementation
{ TComponentA }
procedure TComponentA.Init(const ComponentB: TComponentB);
begin
WriteLn('TComponentA.Init');
end;
{ Routines }
procedure Register(const Container: TContainer);
const
ComponentAContainer = 'ComponentAContainer';
begin
Container.RegisterType<TContainer>(ComponentAContainer).DelegateTo(
function : TContainer
begin
Result := TContainer.Create;
Result.RegisterType<TComponentA, TComponentA>.AsSingleton;
// The inner container invokes `[Inject] TComponentA.Init`.
// This succeeds as the inner container has `TComponentB`
// registered.
// This is the desired mechanism of choice to construct
// the object graph.
Result.RegisterType<TComponentB, TComponentB>;
Result.Build;
end
);
Container.RegisterType<TComponentA>.DelegateTo(
function : TComponentA
var
Temp: TContainer;
begin
Temp := Container.Resolve<TContainer>(ComponentAContainer);
Result := Temp.Resolve<TComponentA>;
end
);
// The outer container invokes `[Inject] TComponentA.Init`, too.
// This does not succeed as the outer container does not have
// `TComponentB` registered.
// In fact, this is not desired anyway, as the inner container
// already constructed the complete object graph for a `TComponentA`
// instance.
// Here only the binding of the lifetimes of Temp and Result are
// supposed to happen (not shown).
end;
procedure Run;
var
Container: TContainer;
ComponentA: TComponentA;
begin
Container := TContainer.Create;
Register(Container);
Container.Build;
ComponentA := Container.Resolve<TComponentA>;
ComponentA := Container.Resolve<TComponentA>;
{ ... }
end;
end.
Примечания. Для простоты в этом примере не учитывается управление временем жизни. Кроме того, внутренний контейнер содержит на самом деле более одного синглтона, и было бы много работы, чтобы вручную связать их с графом объектов и не использовать AsSingleton
из контейнера, что делает его опцией без параметров.