如何向容器未注册的类注入对象?附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




