.NET Core 2.2依赖注入容器:对象构造后如何设置属性
解决.NET Core 2.2中服务构造后属性注入的循环依赖问题
这个场景我太熟悉了,循环依赖确实容易卡壳,尤其是没法通过构造函数注入的情况。咱们可以通过给IServiceCollection写一个扩展方法,来实现你想要的“构造完成后设置属性”的逻辑,具体方案如下:
1. 编写ServiceCollection扩展方法
首先创建一个扩展类,添加一个Inject方法,用来在服务实例化后执行属性注入的逻辑:
using Microsoft.Extensions.DependencyInjection; using System; using System.Linq; public static class ServiceCollectionExtensions { public static IServiceCollection Inject<TService>(this IServiceCollection services, Action<TService, IServiceProvider> configure) where TService : class { // 查找已注册的对应服务描述 var descriptor = services.FirstOrDefault(d => d.ServiceType == typeof(TService)); if (descriptor == null) throw new InvalidOperationException($"服务 {typeof(TService).Name} 未在容器中注册"); // 根据原服务的生命周期,替换为工厂模式注册,实现构造后属性注入 switch (descriptor.Lifetime) { case ServiceLifetime.Singleton: services.Replace(ServiceDescriptor.Singleton<TService>(sp => { var service = (TService)ActivatorUtilities.CreateInstance(sp, descriptor.ImplementationType); configure(service, sp); return service; })); break; case ServiceLifetime.Scoped: services.Replace(ServiceDescriptor.Scoped<TService>(sp => { var service = (TService)ActivatorUtilities.CreateInstance(sp, descriptor.ImplementationType); configure(service, sp); return service; })); break; case ServiceLifetime.Transient: services.Replace(ServiceDescriptor.Transient<TService>(sp => { var service = (TService)ActivatorUtilities.CreateInstance(sp, descriptor.ImplementationType); configure(service, sp); return service; })); break; } return services; } }
2. 在你的服务注册中使用这个扩展
回到你的代码,注册完IServiceA和IServiceB之后,直接调用Inject方法来设置ServiceB的ServiceA属性:
services.AddSingleton<IServiceA, ServiceA>(); services.AddSingleton<IServiceB, ServiceB>(); // 用扩展方法实现构造后的属性注入 services.Inject<IServiceB>((serviceB, serviceProvider) => { serviceB.ServiceA = serviceProvider.GetService<IServiceA>(); });
为什么这个方案能解决循环依赖?
ServiceA的构造函数依赖IServiceB,在创建ServiceA时,IServiceB的实例已经被容器创建(因为都是Singleton生命周期);ServiceB的ServiceA属性是在ServiceB实例化完成后才被设置的,不会触发新的实例创建,完美避开了构造函数层面的循环依赖。
注意事项
- 如果你的服务是
Scoped或Transient生命周期,上面的扩展方法也能适配,因为我们根据原服务的生命周期做了对应的处理; - 确保你注入的属性不会在服务的构造函数中被使用,否则可能会遇到空引用问题——毕竟属性是在构造完成后才设置的。
内容的提问来源于stack exchange,提问作者M T
相关产品推荐
相关产品推荐

