You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何向容器未注册的类注入对象?附Delphi依赖注入示例

解决未注册依赖类TB的DI容器解析问题

嘿,我看你在Delphi依赖注入场景里遇到了个常见问题:TA依赖TB,但你不想注册TB,同时TB又依赖已经注册好的TC。别担心,咱们可以通过两种实用方案搞定这个问题,下面给你一步步拆解:


先明确你的现有代码结构

类定义

TA = class
private
  _b: TB;
public
  constructor Create;
end;

TB = class
private
  _c: TC;
public
  procedure SetC(c: TC);
end;

TC = class
public
  // 这里是TC的具体实现代码
end;

现有容器注册逻辑

procedure Project;
var
  a: TA;
begin
  GlobalContainer.RegisterType<TA>.AsSingleton;
  GlobalContainer.RegisterType<TC>.AsSingleton;
  GlobalContainer.Build;
  a := GlobalContainer.Resolve<TA>; // 这里会报错,因为容器不知道如何创建TB
end;

方案1:自定义工厂方法(推荐,符合DI最佳实践)

核心思路是:注册TA的时候,手动控制TB的实例化,并把已注册的TC注入给TB,再把TB注入给TA。

首先咱们优化下TA的构造函数,让它通过构造注入接收TB(比直接赋值私有成员更规范):

TA = class
private
  _b: TB;
public
  // 修改构造函数,明确依赖TB
  constructor Create(b: TB);
end;

然后修改容器注册代码,用工厂方法实现依赖链的注入:

procedure Project;
var
  a: TA;
begin
  GlobalContainer.RegisterType<TC>.AsSingleton;
  
  // 注册TA时使用工厂逻辑,手动处理TB的创建和依赖注入
  GlobalContainer.RegisterType<TA>.AsSingleton.UsingFactory(
    function: TA
    var
      targetTB: TB;
      targetTC: TC;
    begin
      // 从容器获取已注册的单例TC
      targetTC := GlobalContainer.Resolve<TC>;
      
      // 实例化TB并注入TC
      targetTB := TB.Create;
      targetTB.SetC(targetTC);
      
      // 实例化TA并注入TB
      Result := TA.Create(targetTB);
    end
  );

  GlobalContainer.Build;
  a := GlobalContainer.Resolve<TA>; // 现在可以正常解析TA了
end;

方案2:利用容器的自动属性注入(如果容器支持)

如果你的DI容器(比如Spring4D这类)支持自动属性注入和未注册类的实例化,咱们可以通过标记注入点来简化操作:

首先给TB和TA添加可注入的属性:

TB = class
private
  _c: TC;
public
  // 标记这个属性为注入点,容器会自动注入TC
  [Inject]
  property C: TC read _c write SetC;
end;

TA = class
private
  _b: TB;
public
  // 标记这个属性为注入点,容器会自动实例化TB并注入
  [Inject]
  property B: TB read _b write _b;
end;

然后调整注册代码,启用自动注入配置:

procedure Project;
var
  a: TA;
begin
  GlobalContainer.RegisterType<TA>.AsSingleton;
  GlobalContainer.RegisterType<TC>.AsSingleton;
  
  // 启用自动属性注入(不同容器的配置语法可能略有差异)
  GlobalContainer.Configure<TInjector>.AutoWire;

  GlobalContainer.Build;
  a := GlobalContainer.Resolve<TA>; // 容器会自动处理TB的实例化和依赖注入
end;

小小总结

  • 优先选方案1,构造注入的方式让依赖关系更清晰,代码也更容易测试和维护;
  • 如果你用的容器支持自动注入,方案2会更简洁,适合快速实现。

内容的提问来源于stack exchange,提问作者aQuu

火山引擎 最新活动