.NET 7中如何避免派生类重复编写与基类一致的构造函数?
解决方案与问题解答
1. 无需在派生类构造函数声明依赖的注入方式
可以通过基类依赖IServiceProvider解析所需服务,避免派生类重复传递多组依赖参数。修改基类构造函数仅接收IServiceProvider,在基类内部自行解析ILogger<DerivedClient>、IOptions<MyOptions>和IConfiguration,派生类只需保留极简构造函数即可。
修改后的基类示例:
[ApiController] [Route("[controller]")] public abstract class MyBaseController<DerivedClient, MyRequest, MyResponse> : ControllerBase where DerivedClient : HttpClient, new() { protected DerivedClient _derivedClient; protected readonly ILogger<DerivedClient> _logger; public IConfiguration _configuration; protected IOptions<MyOptions> _options; public abstract Func<MyRequest, Task<MyResponse>> MyClientDelegate { get; } protected MyBaseController(IServiceProvider serviceProvider) { _derivedClient = new(); _logger = serviceProvider.GetRequiredService<ILogger<DerivedClient>>(); _options = serviceProvider.GetRequiredService<IOptions<MyOptions>>(); _configuration = serviceProvider.GetRequiredService<IConfiguration>(); } [HttpGet, Route("GetTheData")] public Task<MyResponse> GetTheData(MyRequest request) { return MyClientDelegate(request); } }
派生类简化为:
public class A : MyBaseController<AClient, string, string> { public A(IServiceProvider serviceProvider) : base(serviceProvider) { } public override Func<string, Task<string>> MyClientDelegate => _derivedClient.GetDataA; }
如果想进一步简化,可借助ActivatorUtilities让ASP.NET Core自动解析IServiceProvider,但显式编写极简构造函数更稳妥,避免激活异常。另外,属性注入虽能实现,但ASP.NET Core默认不支持控制器属性注入,需自定义激活器,不推荐用于核心依赖。
2. .NET 7(C# 11)是否支持继承基类构造函数
C#自诞生起就不支持自动继承基类构造函数——仅当基类包含无参构造函数时,派生类才会默认调用它。.NET 7对应的C# 11版本也未添加该特性,因此仍需在派生类中显式调用基类构造函数,无法直接省略。
3. 是否应将构造函数依赖迁移至服务类
该方案完全可行,尤其适合依赖较多的场景。可将客户端及所需依赖封装为泛型服务类,统一管理依赖,控制器只需注入该泛型服务,大幅减少构造函数参数数量。
示例步骤:
- 创建泛型服务类:
public class ClientService<DerivedClient> where DerivedClient : HttpClient, new() { public DerivedClient Client { get; } public ILogger<DerivedClient> Logger { get; } public IOptions<MyOptions> Options { get; } public IConfiguration Configuration { get; } public ClientService(ILogger<DerivedClient> logger, IOptions<MyOptions> options, IConfiguration configuration) { Client = new DerivedClient(); Logger = logger; Options = options; Configuration = configuration; } }
- 在Program.cs中注册泛型服务:
builder.Services.AddScoped(typeof(ClientService<>));
- 修改基类构造函数,仅注入泛型服务:
protected MyBaseController(ClientService<DerivedClient> clientService) { _derivedClient = clientService.Client; _logger = clientService.Logger; _options = clientService.Options; _configuration = clientService.Configuration; }
- 派生类简化为:
public class A : MyBaseController<AClient, string, string> { public A(ClientService<AClient> clientService) : base(clientService) { } public override Func<string, Task<string>> MyClientDelegate => _derivedClient.GetDataA; }
这种方式的优势在于:后续新增依赖时,仅需修改ClientService的构造函数与注册逻辑,所有派生类无需改动,符合开闭原则。
内容的提问来源于stack exchange,提问作者William YK
相关产品推荐
相关产品推荐

