一、依赖注入核心原理
1. 控制反转(IoC)与DI关系
- 控制反转(IoC):框架控制程序流程,而非开发者
- 依赖注入(DI):IoC的一种实现方式,通过外部提供依赖对象
2. .NET DI核心组件
-
IServiceCollection
:服务注册容器 -
IServiceProvider
:服务解析器 -
ServiceDescriptor
:服务描述符(包含生命周期信息)
二、服务生命周期
三种生命周期类型
生命周期 | 描述 | 适用场景 |
---|---|---|
Transient | 每次请求创建新实例 | 轻量级、无状态服务 |
Scoped | 同一作用域内共享实例 | Web请求上下文 |
Singleton | 全局单例 | 配置服务、缓存 |
// 注册示例 services.AddTransient(); services.AddScoped(); services.AddSingleton();
三、DI容器实现原理
1. 服务注册流程
public static IServiceCollection AddTransient(this IServiceCollection services) { // 创建服务描述符 var descriptor = new ServiceDescriptor( typeof(TService), typeof(TImplementation), ServiceLifetime.Transient); // 添加到集合 services.Add(descriptor); return services; }
2. 服务解析流程
public object GetService(Type serviceType) { // 1. 查找服务描述符 var descriptor = _descriptors.FirstOrDefault(d => d.ServiceType == serviceType); // 2. 根据生命周期创建实例 if (descriptor.Lifetime == ServiceLifetime.Singleton) { if (_singletons.TryGetValue(serviceType, out var instance)) return instance; instance = CreateInstance(descriptor); _singletons[serviceType] = instance; return instance; } // ...处理Scoped和Transient }
四、高级实现方法
1. 工厂模式注册
services.AddTransient(provider => { var otherService = provider.GetRequiredService(); return new ServiceImpl(otherService, "参数"); });
2. 泛型服务注册
services.AddTransient(typeof(IRepository), typeof(Repository));
3. 多实现解决方案
// 注册多个实现 services.AddTransient(); services.AddTransient(); // 解析时获取所有实现 var services = provider.GetServices();
五、ASP.NET Core中的DI集成
1. 控制器注入
public class HomeController : Controller { private readonly ILogger _logger; public HomeController(ILogger logger) { _logger = logger; // 自动注入 } }
2. 视图注入
@inject IConfiguration Config当前环境: @Config["Environment"]
3. 中间件注入
public class CustomMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; public CustomMiddleware( RequestDelegate next, ILogger logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { // 使用注入的服务 _logger.LogInformation("中间件执行"); await _next(context); } }
六、自定义DI容器实现
1. 简易DI容器实现
public class SimpleContainer : IServiceProvider { private readonly Dictionary _descriptors; public SimpleContainer(IEnumerable descriptors) { _descriptors = descriptors.ToDictionary(x => x.ServiceType); } public object GetService(Type serviceType) { if (!_descriptors.TryGetValue(serviceType, out var descriptor)) return null; if (descriptor.ImplementationInstance != null) return descriptor.ImplementationInstance; var type = descriptor.ImplementationType ?? descriptor.ServiceType; return ActivatorUtilities.CreateInstance(this, type); } }
2. 属性注入实现
public static class PropertyInjectionExtensions { public static void AddPropertyInjection(this IServiceCollection services) { services.AddTransient(); } } public class PropertyInjectionStartupFilter : IStartupFilter { public Action Configure(Action next) { return builder => { builder.Use(async (context, nextMiddleware) => { var endpoint = context.GetEndpoint(); if (endpoint?.Metadata.GetMetadata() is { } descriptor) { var controller = context.RequestServices.GetRequiredService(descriptor.ControllerTypeInfo); // 反射实现属性注入 InjectProperties(controller, context.RequestServices); } await nextMiddleware(); }); next(builder); }; } private void InjectProperties(object target, IServiceProvider services) { var properties = target.GetType().GetProperties() .Where(p => p.CanWrite && p.GetCustomAttribute() != null); foreach (var prop in properties) { var service = services.GetService(prop.PropertyType); if (service != null) prop.SetValue(target, service); } } }
七、最佳实践
1. 服务设计原则
- 遵循显式依赖原则
- 避免服务定位 器模式(反模式)
- 保持服务轻量级
2. 常见陷阱
// 错误示例:捕获Scoped服务到Singleton中 services.AddSingleton(provider => { var scopedService = provider.GetRequiredService(); // 危险! return new BackgroundService(scopedService); }); // 正确做法:使用IServiceScopeFactory services.AddSingleton(provider => { var scopeFactory = provider.GetRequiredService(); return new BackgroundService(scopeFactory); });
八、性能优化
1. 避免过度注入
// 不好:注入过多服务 public class OrderService( ILogger logger, IEmailService emailService, ISmsService smsService, IRepository repo, ICache cache, IConfig config) { // ... } // 改进:使用聚合服务 public class OrderService( ILogger logger, INotificationService notification, IOrderInfrastructure infra) { // ... }
2. 编译时注入
[RegisterTransient(typeof(IMyService))] public class MyService : IMyService { // ... } // 使用Source Generator自动生成注册代码 static partial class ServiceRegistration { static partial void AddGeneratedServices(IServiceCollection services) { services.AddTransient(); } }
.NET的依赖注入系统是框架的核心基础设施,理解其原理和实现方式有助于编写更可测试、更松耦合的应用程序。
到此这篇关于全面解析.NET中的依赖注入(DI)的文章就介绍到这了,更多相关.NET依赖注入DI内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!