如果Container1无法解析T,如何将Container1.Resolve <t>委托给Container2.Resolve <t>?

时间:2017-09-23 22:51:02

标签: dependency-injection spring4d

使用Spring4D,我想建立一个容器,将服务解析委托给另一个容器,如果它无法解析服务 - 这就是这些:

function TContainer.Resolve<T>: T;
begin
  if not TryResolve<T>(Result) then
    Result := OtherContainer.Resolve<T>;
end;

这可能吗?

1 个答案:

答案 0 :(得分:1)

在处理特定类型或类型模式的容器中有所谓的子依赖关系解析器(未来版本将只调用它们类型解析器)(比如能够解析TArray<T>IList<T>其中T是什么正在注册)。

您可以实现自己的检查,如果某个类型不在您将此解析器附加到的容器内,然后将此类型的解析链委托给另一个容器。

以下是一些示例代码如何实现(不释放对象)

uses
  Spring,
  Spring.Container,
  Spring.Container.Core,
  System.SysUtils;

type
  TFoo = class

  end;

  TBar = class
  private
    fFoo: TFoo;
  public
    constructor Create(const foo: TFoo);
    property Foo: TFoo read fFoo;
  end;

  TSubContainerResolver = class(TInterfacedObject, ISubDependencyResolver)
  private
    fContainer: TContainer;
    fSubContainer: TContainer;
  public
    constructor Create(const container, subContainer: TContainer);

    function CanResolve(const context: ICreationContext;
      const dependency: TDependencyModel; const argument: TValue): Boolean;
    function Resolve(const context: ICreationContext;
      const dependency: TDependencyModel; const argument: TValue): TValue;
  end;

{ TBar }

constructor TBar.Create(const foo: TFoo);
begin
  fFoo := foo;
end;

{ TSubContainerResolver }

constructor TSubContainerResolver.Create(const container, subContainer: TContainer);
begin
  fContainer := container;
  fSubContainer := subContainer;
end;

function TSubContainerResolver.CanResolve(const context: ICreationContext;
  const dependency: TDependencyModel; const argument: TValue): Boolean;
begin
  Result := not fContainer.Kernel.Registry.HasService(dependency.TypeInfo)
    and fSubContainer.Kernel.Resolver.CanResolve(context, dependency, argument);
end;

function TSubContainerResolver.Resolve(const context: ICreationContext;
  const dependency: TDependencyModel; const argument: TValue): TValue;
begin
  Result := fSubContainer.Kernel.Resolver.Resolve(context, dependency, argument);
end;

procedure ScenarioOne;
var
  c1, c2: TContainer;
  b: TBar;
begin
  c1 := TContainer.Create;
  c2 := TContainer.Create;
  c1.Kernel.Resolver.AddSubResolver(TSubContainerResolver.Create(c1, c2));

  // dependency in subcontainer
  c1.RegisterType<TBar>;
  c1.Build;
  c2.RegisterType<TFoo>;
  c2.Build;

  b := c1.Resolve<TBar>;
  Assert(Assigned(b.fFoo));
end;

procedure ScenarioTwo; 
var
  c1, c2: TContainer;
  b: TBar;
begin
  c1 := TContainer.Create;
  c2 := TContainer.Create;

  c1.Kernel.Resolver.AddSubResolver(TSubContainerResolver.Create(c1, c2));
  c2.Kernel.Resolver.AddSubResolver(TSubContainerResolver.Create(c2, c1));

  // type in subcontainer but dependency in parent container
  c1.RegisterType<TFoo>;
  c1.Build;
  c2.RegisterType<TBar>;
  c2.Build;

  b := c1.Resolve<TBar>;
  Assert(Assigned(b.fFoo));
end;

begin
  ScenarioOne;
  ScenarioTwo;
end.