You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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. 是否应将构造函数依赖迁移至服务类

该方案完全可行,尤其适合依赖较多的场景。可将客户端及所需依赖封装为泛型服务类,统一管理依赖,控制器只需注入该泛型服务,大幅减少构造函数参数数量。

示例步骤:

  1. 创建泛型服务类:
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;
    }
}
  1. 在Program.cs中注册泛型服务:
builder.Services.AddScoped(typeof(ClientService<>));
  1. 修改基类构造函数,仅注入泛型服务:
protected MyBaseController(ClientService<DerivedClient> clientService)
{
    _derivedClient = clientService.Client;
    _logger = clientService.Logger;
    _options = clientService.Options;
    _configuration = clientService.Configuration;
}
  1. 派生类简化为:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 07:25:17