在使用DI时,难免会出现两个服务互相依赖的情况(互相出现在对方的构造函数中)
报错信息:A circular dependency was detected for the service of type 'xxx'
遇到这个,联想到.net自带的Lazy类,可以按需延迟构造对象。我们可以用类似的思路解决循环依赖。编写如下代码,定义一个延迟注入的依赖:
public class LazyInject<T>(IServiceProvider sp) where T : class
{
public T Value { get
{
return sp.GetRequiredService<T>();
}
}
}
在互相依赖对方的服务的构造函数中不写对方的类型T,而是LazyInject<T>,这样就不会引发循环依赖的报错。不在构造时立即要求填入对方实例,而是在使用到时再从服务容器获取对方的示例。
public class SvcA(LazyInject<SvcB> svcB)
{
public xxx Xxxxx(string? search)
{
svcB.Value.xxxxx....//使用.Value getter获取SvcB实例
}
}
注:上述代码是新版C#的“主构造函数”语法,旧版C#应单独写构造函数。
记得在应用启动时,SvcB与LazyInject<SvcB>都要加入到服务容器中。
当然,这只是在“类的层面”上避免了循环依赖,如果真的有逻辑上的循环依赖,那是无济于事的。