C# Discord机器人开发:Reaction事件如何获取对应消息
Discord.Net 反应事件获取目标消息对象解决方案
问题背景
开发Discord机器人时需要实现以下逻辑:用户对某条消息添加表情反应时,机器人自动将该消息转发至指定频道。实际开发中无法正确获取被添加反应的目标消息内容,尝试传入message、message.GetOrDownloadAsync、message.DownloadAsync、reaction.Message等取值,均无法得到正确消息对象,仅返回类似System.Func1[System.Threading.Tasks.Task1[Discord.IUserMessage]]的结果。
相关业务初始代码如下:
private async Task MainAsyns() { _client.ReactionAdded += HandleReaction; } private async Task HandleReaction(Cacheable<IUserMessage, ulong> message, Cacheable<IMessageChannel, ulong> channel, SocketReaction reaction) { var toOtherChanel = _client.GetChannel(_toOtherChanelId) as IMessageChannel; var msg = ???; if (!_client.GetUser(reaction.UserId).IsBot) { if (reaction.Emote.Name == "\uD83D\uDC4D") { await toOtherChanel.SendMessageAsync($"Message is {msg}"); } } }
错误原因
GetOrDownloadAsync、DownloadAsync都是异步方法,直接传入方法名不加await关键字等待执行结果,拿到的是方法本身的委托/Task对象,不是执行完成后的消息实例,才会打印出Func类型的字符串。reaction.Message属性依赖本地缓存,反应事件触发时关联消息大概率未被加载到缓存,会返回null,不适合直接使用。
正确实现
???位置的正确写法为await message.GetOrDownloadAsync(),该方法会优先从本地缓存读取消息对象,缓存不存在时自动调用Discord API拉取完整消息数据。
优化后完整代码
private async Task MainAsync() { _client.ReactionAdded += HandleReaction; } private async Task HandleReaction(Cacheable<IUserMessage, ulong> message, Cacheable<IMessageChannel, ulong> channel, SocketReaction reaction) { var toOtherChanel = _client.GetChannel(_toOtherChanelId) as IMessageChannel; // 正确获取目标消息对象 var msg = await message.GetOrDownloadAsync(); // 优化用户获取逻辑,避免缓存为空触发空引用异常 var reactionUser = await reaction.User.GetOrDownloadAsync(); if (!reactionUser.IsBot && reaction.Emote.Name == "\uD83D\uDC4D") { // 通过msg.Content获取消息正文,直接插值msg对象默认调用ToString()不会返回正文内容 await toOtherChanel.SendMessageAsync($"Message is {msg.Content}"); } }
注意事项
- 所有返回
Task类型的异步方法必须加await关键字等待执行完成,才能拿到预期的返回值 - 事件参数里的
Cacheable类型是Discord.Net专门设计的缓存兼容结构,优先使用GetOrDownloadAsync()方法获取实例,不要直接依赖缓存读取 - 获取消息正文需要访问
IUserMessage的Content属性,直接对消息对象做字符串插值默认会调用类型的ToString()方法,不会返回实际消息内容
内容的提问来源于stack exchange,提问作者retusu
相关产品推荐
相关产品推荐

