如何解决.NET Core DI中业务服务的循环引用问题
解决DI循环依赖的可行方案
1. 延迟注入(Lazy)
用Lazy<T>包装依赖,让DI容器在创建服务时不立即解析依赖,直到第一次调用依赖对象的方法时才完成实例化,打破循环创建的死锁。
修改CarService的代码:
public class CarService { private readonly CarRepository _carRepository; private readonly Lazy<RecallService> _recallService; public CarService(CarRepository carRepository, Lazy<RecallService> recallService) { _carRepository = carRepository; _recallService = recallService; } public void RemoveRecallForCar(Recall recall) { // code } public void SendRecall(Guid carGuid) { Car car = _carRepository.Get(carGuid); if (car.Model == "Ford") { // 首次访问Value时才会实例化RecallService _recallService.Value.SendRecall(carGuid); } } }
RecallService保持原有构造函数即可(也可以选择在RecallService里用Lazy包装CarService,选一侧实现即可)。主流DI容器(如Microsoft.Extensions.DependencyInjection、Autofac)都原生支持Lazy<T>的解析,无需额外配置。
2. 重构业务逻辑,引入协调层
将两个服务交叉调用的逻辑提取到新的上层协调服务,让CarService和RecallService专注自身核心职责,不再直接依赖彼此。
比如创建RecallOrchestrator协调服务:
public class RecallOrchestrator { private readonly CarService _carService; private readonly RecallService _recallService; public RecallOrchestrator(CarService carService, RecallService recallService) { _carService = carService; _recallService = recallService; } // 原CarService中的SendRecall逻辑迁移至此 public void SendRecallForFord(Guid carGuid) { Car car = _carService.GetCar(carGuid); // 给CarService新增GetCar方法暴露数据 if (car.Model == "Ford") { _recallService.SendRecall(carGuid); } } // 原RecallService中的GetRecalls逻辑迁移至此 public void ProcessActiveRecalls() { List<Recall> recalls = _recallService.GetActiveRecalls(); // 给RecallService新增获取活跃召回的方法 foreach(var recall in recalls) { _carService.RemoveRecallForCar(recall); } } }
然后修改两个基础服务,移除互相依赖:
// 修改后的CarService public class CarService { private readonly CarRepository _carRepository; public CarService(CarRepository carRepository) { _carRepository = carRepository; } public Car GetCar(Guid carGuid) { return _carRepository.Get(carGuid); } public void RemoveRecallForCar(Recall recall) { // code } }
// 修改后的RecallService public class RecallService { private readonly RecallRepository _recallRepository; public RecallService(RecallRepository recallRepository) { _recallRepository = recallRepository; } public void SendRecall(Guid carGuid) { // recall code } public List<Recall> GetActiveRecalls() { return _recallRepository.Fetch(x => x.IsActive).ToList(); } }
3. 属性注入(谨慎使用)
将其中一个依赖从构造函数移到属性,让DI容器先创建服务实例,再注入属性。这种方法简单但不推荐过度使用——它会让依赖关系不明确,容易出现空引用问题。
比如修改RecallService:
public class RecallService { private readonly RecallRepository _recallRepository; // 根据DI容器规则标记可注入属性(如Microsoft DI用[FromServices],Autofac用[Inject]) public CarService CarService { get; set; } public RecallService(RecallRepository recallRepository) { _recallRepository = recallRepository; } public void SendRecall(Guid carGuid) { // recall code } public void GetRecalls() { List<Recall> recalls = _recallRepository.Fetch(x => x.IsActive).ToList(); foreach(var recall in recalls) { CarService.RemoveRecallForCar(recall); } } }
需要注意:部分DI容器需要手动启用属性注入功能,配置方式需参考对应容器文档。
4. 提取接口+工厂模式
为服务定义接口,注入工厂函数而非直接注入实例,延迟依赖的创建时机。
首先为两个服务定义接口:
public interface IRecallService { void SendRecall(Guid carGuid); } public interface ICarService { void RemoveRecallForCar(Recall recall); }
修改服务实现,注入工厂函数:
public class CarService : ICarService { private readonly CarRepository _carRepository; private readonly Func<IRecallService> _recallServiceFactory; // 注入工厂函数替代直接实例 public CarService(CarRepository carRepository, Func<IRecallService> recallServiceFactory) { _carRepository = carRepository; _recallServiceFactory = recallServiceFactory; } public void RemoveRecallForCar(Recall recall) { // code } public void SendRecall(Guid carGuid) { Car car = _carRepository.Get(carGuid); if (car.Model == "Ford") { // 需要时通过工厂创建实例 var recallService = _recallServiceFactory(); recallService.SendRecall(carGuid); } } } public class RecallService : IRecallService { private readonly RecallRepository _recallRepository; private readonly ICarService _carService; public RecallService(RecallRepository recallRepository, ICarService carService) { _recallRepository = recallRepository; _carService = carService; } public void SendRecall(Guid carGuid) { // recall code } public void GetRecalls() { List<Recall> recalls = _recallRepository.Fetch(x => x.IsActive).ToList(); foreach(var recall in recalls) { _carService.RemoveRecallForCar(recall); } } }
在DI容器中注册接口与实现类即可,主流容器会自动解析Func<T>作为实例工厂。
内容的提问来源于stack exchange,提问作者Dicpherrr
相关产品推荐
相关产品推荐

