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

ASP.NET Telegram Bot:泛型类绕过无参构造函数限制方案

解决方案

首先明确:C#不支持带参数的new()泛型约束,你写的new(IServiceProvider provider)是无效语法,无法通过编译。下面是适配依赖注入的修正方案:

1. 修改UpdateDistributor<T>,通过服务提供者创建实例

移除new()泛型约束,改为在构造函数中注入IServiceProvider,用它来创建T的实例,而非直接new T():

public class UpdateDistributor<T> where T : ITelegramUpdateListener
{
    private Dictionary<long, T>? _listeners;
    private readonly IServiceProvider _serviceProvider;

    // 注入服务提供者
    public UpdateDistributor(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
        _listeners = new Dictionary<long, T>();
    }

    public async Task GetUpdate(Update update)
    {
        long chatId = update.Message.Chat.Id;
        T? listener = _listeners.GetValueOrDefault(chatId);
    
        if (listener is null) 
        {
            // 通过服务提供者获取T的实例
            listener = _serviceProvider.GetRequiredService<T>();
            _listeners.Add(chatId, listener);
            await listener.GetUpdate(update);
            return;
        }

        await listener.GetUpdate(update);
    }

    public void AddListener(Update update, T listener)
    {
        _listeners.Add(update.Message.Chat.Id, listener);
    }
}

2. 注册相关服务到DI容器

在ASP.NET的Program.cs(或Startup配置类)中,将CommandExecutor及它的依赖注册到依赖注入容器:

// 注册CommandExecutor为瞬态服务
builder.Services.AddTransient<CommandExecutor>();

// 确保CommandExecutor依赖的仓储已注册
builder.Services.AddScoped<IRepository<UserSubscription>, UserSubscriptionRepository>();
builder.Services.AddScoped<IRepository<BotService>, BotServiceRepository>();

// 注册UpdateDistributor
builder.Services.AddTransient(typeof(UpdateDistributor<>));

3. 修改BotController,通过构造函数注入依赖

不再手动实例化UpdateDistributor,改为让DI容器自动注入:

public class BotController : Controller
{
    private readonly TelegramBotClient _bot;
    private readonly UpdateDistributor<CommandExecutor> _updateDistributor;

    // 构造函数注入所需依赖
    public BotController(UpdateDistributor<CommandExecutor> updateDistributor)
    {
        _bot = Bot.GetTelegramBot();
        _updateDistributor = updateDistributor;
        BotOptions.SetOptions();
    }

    [HttpPost]
    public async Task Post(Update update) // 替换async void为async Task,避免异步生命周期问题
    {
        if (update.Message == null) 
            return;

        await _updateDistributor.GetUpdate(update);
    }
}

额外优化提示

  • 控制器Action避免使用async void,改用async Task能更好地适配ASP.NET的异步请求生命周期,减少潜在的资源泄漏风险。
  • 如果需要每个聊天ID对应唯一的CommandExecutor实例,当前通过Dictionary<long, T>存储的逻辑已经可以满足需求,无需额外调整。

内容的提问来源于stack exchange,提问作者Roman Blackbrock

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 17:43:15