如何通过依赖注入实现基于条件的IReportGenerator实例化?
问题解决:移除IReportGenerator实例化中的new关键字
问题背景
已定义IReportGenerator接口及APReportGenerator、ARReportGenerator两个实现类,原AccountController的Submit方法通过switch语句+new关键字根据ActivityReport.Type实例化对应实现类。希望移除new关键字,已在Startup.cs中注册了两个Scoped生命周期的IReportGenerator实现,但不清楚控制器如何正确获取对应实例。
解决方案
方案1:注入所有实现类并动态匹配
ASP.NET Core支持直接注入IEnumerable<IReportGenerator>,会自动将所有注册的IReportGenerator实现实例注入进来,之后可根据类型名称匹配获取对应实例。
1. 保持服务注册(或优化)
在Startup.cs中注册两个实现类:
services.AddScoped<IReportGenerator, APReportGenerator>(); services.AddScoped<IReportGenerator, ARReportGenerator>();
注:ASP.NET Core会自动收集所有注册的
IReportGenerator实现,注入IEnumerable<IReportGenerator>时会包含这两个实例。
2. 修改控制器代码
注入IEnumerable<IReportGenerator>,并在Submit方法中根据Type字段匹配对应生成器:
public class AccountController : Controller { private readonly IEnumerable<IReportGenerator> _reportGenerators; // 修正原代码中的拼写错误:AccounterController → AccountController public AccountController(IEnumerable<IReportGenerator> reportGenerators) { _reportGenerators = reportGenerators; } [HttpPost] public IActionResult Submit(ActivityReport activityReport) { // 根据Type字段匹配对应的Generator类名(如"AR"对应ARReportGenerator) var reportGenerator = _reportGenerators.FirstOrDefault(g => g.GetType().Name.Equals($"{activityReport.Type}ReportGenerator", StringComparison.OrdinalIgnoreCase)); if (reportGenerator == null) { return BadRequest($"不支持的报告类型:{activityReport.Type}"); } reportGenerator.Process(activityReport); // 后续业务逻辑 return Ok(); } }
方案2:使用工厂模式封装实例获取逻辑
创建专门的工厂类负责根据类型获取对应生成器,将实例化逻辑集中管理,更易维护。
1. 注册服务与工厂
在Startup.cs中注册具体实现类和工厂类:
// 注册具体的生成器实现 services.AddScoped<APReportGenerator>(); services.AddScoped<ARReportGenerator>(); // 注册工厂类 services.AddScoped<ReportGeneratorFactory>();
2. 实现工厂类
public class ReportGeneratorFactory { private readonly IServiceProvider _serviceProvider; public ReportGeneratorFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IReportGenerator GetGenerator(string reportType) { return reportType switch { "AR" => _serviceProvider.GetRequiredService<ARReportGenerator>(), "AP" => _serviceProvider.GetRequiredService<APReportGenerator>(), _ => throw new ArgumentException($"不支持的报告类型:{reportType}") }; } }
3. 修改控制器代码
注入工厂类,通过工厂获取对应生成器:
public class AccountController : Controller { private readonly ReportGeneratorFactory _generatorFactory; public AccountController(ReportGeneratorFactory generatorFactory) { _generatorFactory = generatorFactory; } [HttpPost] public IActionResult Submit(ActivityReport activityReport) { try { var reportGenerator = _generatorFactory.GetGenerator(activityReport.Type); reportGenerator.Process(activityReport); // 后续业务逻辑 return Ok(); } catch (ArgumentException ex) { return BadRequest(ex.Message); } } }
注意事项
- 原代码中控制器构造函数存在拼写错误:
AccounterController应改为AccountController,需修正。 - 两种方案均完全移除了
new关键字,依赖ASP.NET Core的DI容器管理实例生命周期,符合依赖注入原则。
内容的提问来源于stack exchange,提问作者blue piranha
相关产品推荐
相关产品推荐

