You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 03:27:39