文章目錄
- 一、依賴注入核心原理
- 1. 控制反轉(IoC)與DI關系
- 2. .NET DI核心組件
- 二、服務生命周期
- 1. 三種生命周期類型
- 三、DI容器實現原理
- 1. 服務注冊流程
- 2. 服務解析流程
- 四、高級實現方法
- 1. 工廠模式注冊
- 2. 泛型服務注冊
- 3. 多實現解決方案
- 五、ASP.NET Core中的DI集成
- 1. 控制器注入
- 2. 視圖注入
- 3. 中間件注入
- 六、自定義DI容器實現
- 1. 簡易DI容器實現
- 2. 屬性注入實現
- 七、最佳實踐
- 1. 服務設計原則
- 2. 常見陷阱
- 八、性能優化
- 1. 避免過度注入
- 2. 編譯時注入

一、依賴注入核心原理
1. 控制反轉(IoC)與DI關系
- 控制反轉(IoC):框架控制程序流程,而非開發者
- 依賴注入(DI):IoC的一種實現方式,通過外部提供依賴對象
2. .NET DI核心組件
IServiceCollection
:服務注冊容器IServiceProvider
:服務解析器ServiceDescriptor
:服務描述符(包含生命周期信息)
二、服務生命周期
1. 三種生命周期類型
生命周期 | 描述 | 適用場景 |
---|---|---|
Transient | 每次請求創建新實例 | 輕量級、無狀態服務 |
Scoped | 同一作用域內共享實例 | Web請求上下文 |
Singleton | 全局單例 | 配置服務、緩存 |
// 注冊示例
services.AddTransient<ITransientService, TransientService>();
services.AddScoped<IScopedService, ScopedService>();
services.AddSingleton<ISingletonService, SingletonService>();
三、DI容器實現原理
1. 服務注冊流程
public static IServiceCollection AddTransient<TService, TImplementation>(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<IService>(provider => {var otherService = provider.GetRequiredService<IOtherService>();return new ServiceImpl(otherService, "參數");
});
2. 泛型服務注冊
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
3. 多實現解決方案
// 注冊多個實現
services.AddTransient<IMessageService, EmailService>();
services.AddTransient<IMessageService, SmsService>();// 解析時獲取所有實現
var services = provider.GetServices<IMessageService>();
五、ASP.NET Core中的DI集成
1. 控制器注入
public class HomeController : Controller
{private readonly ILogger _logger;public HomeController(ILogger<HomeController> logger){_logger = logger; // 自動注入}
}
2. 視圖注入
@inject IConfiguration Config
<p>當前環境: @Config["Environment"]</p>
3. 中間件注入
public class CustomMiddleware
{private readonly RequestDelegate _next;private readonly ILogger _logger;public CustomMiddleware(RequestDelegate next,ILogger<CustomMiddleware> 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<Type, ServiceDescriptor> _descriptors;public SimpleContainer(IEnumerable<ServiceDescriptor> 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<IStartupFilter, PropertyInjectionStartupFilter>();}
}public class PropertyInjectionStartupFilter : IStartupFilter
{public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next){return builder =>{builder.Use(async (context, nextMiddleware) =>{var endpoint = context.GetEndpoint();if (endpoint?.Metadata.GetMetadata<ControllerActionDescriptor>() 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<InjectAttribute>() != 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<IBackgroundService>(provider => {var scopedService = provider.GetRequiredService<IScopedService>(); // 危險!return new BackgroundService(scopedService);
});// 正確做法:使用IServiceScopeFactory
services.AddSingleton<IBackgroundService>(provider => {var scopeFactory = provider.GetRequiredService<IServiceScopeFactory>();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<IMyService, MyService>();}
}
.NET的依賴注入系統是框架的核心基礎設施,理解其原理和實現方式有助于編寫更可測試、更松耦合的應用程序。