如何在Spring4D中实现带有作用域的上下文?

编程语言 2026-07-10

我希望能够注册一个带作用域寿命的单例,其工作方式类似TSingletonPerThreadLifetimeManager,但在超出作用域时会被释放。

我想具备在一个作用域的上下文中,将某些对象视为单例。

在下面的示例中,ContextTTestTSub 都使用。我希望它们都指向同一个实例,但彼此不知晓对方也在使用它。

type
  TSub = class(TInterfacedObject, ISub)
  public
    constructor Create(Context: IContext);
  end;

  TTest = class(TInterfacedObject, ITest)
  public
    constructor Create(Context: IContext; Sub: ISub);
  end;

Container.RegisterType<IContext,TContext>.AsScoped;
Container.RegisterType<ITest,TTest>.AsTransient;
Container.RegisterType<ISub,TSub>.AsTransient;

var Scope:=TScope.New;
try
  var test:=Container.Resolve<ITest>();
  test.execute;
finally
  Scope:=nil;
end;

理想情况下,我不想在作用域内直接引用容器,而是处理传入的动态工厂,例如:

procedure DoInScope(TestFactory: Func<ITest>);
begin
  var Scope:=TScope.New;
  try
    TestFactory().Execute;
  finally
    Scope:=nil;
  end;
end;

我看过TSingletonPerThreadLifetimeManager,但无法弄清楚如何在作用域结束时释放引用。

另一种我能想到的选项是使用委托,例如:

Container.RegisterType<IContext,TContext>.DelegateTo(
  function: IContext
  begin
    if TScope.InScope then
    begin
      if not TScope.Has<IContext> then
        TScope.Add<IContext>(Container.Resolve<IContext>); // wont work as recursive
      Result:=TScope.Get<IContext>;
    end;
  end
);

解决方案

没有带作用域寿命的生命周期,只有按解析创建实例的生命周期。

uses
  Spring.Container;

type
  ISub = interface
  end;

  ITest = interface
  end;

  IContext = interface
  end;

  TContext = class(TInterfacedObject, IContext)
  public
    constructor Create;
  end;

  TSub = class(TInterfacedObject, ISub)
  private
    fContext: IContext;
  public
    constructor Create(Context: IContext);
  end;

  TTest = class(TInterfacedObject, ITest)
  private
    fContext: IContext;
  public
    constructor Create(Context: IContext; Sub: ISub);
  end;

constructor TContext.Create;
begin
  Writeln('creating context');
end;

constructor TSub.Create(Context: IContext);
begin
  Writeln('creating sub');
  fContext := Context;
end;

constructor TTest.Create(Context: IContext; Sub: ISub);
begin
  Writeln('creating test');
  fContext := Context;
end;

begin
  GlobalContainer.RegisterType<IContext,TContext>.PerResolve;
  GlobalContainer.RegisterType<ITest,TTest>.AsTransient;
  GlobalContainer.RegisterType<ISub,TSub>.AsTransient;
  GlobalContainer.Build;

  GlobalContainer.Resolve<ITest>();
end.

将输出如下:

creating context
creating sub
creating test
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章