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
相关产品推荐
相关产品推荐

