C#开发Discord机器人检测游戏分配角色空引用错误如何修复
问题原因
当用户退出所有游戏后,SocketGuildUser.Activity 属性会返回null,你通过as Game转换后得到的Game变量为null,后续直接访问Game.Name就会触发NullReferenceException空引用异常。
除此之外原代码还有多处可优化的冗余逻辑:
- 已经拿到事件参数
after(更新后的用户实例),不需要重复调用GetGuild、GetUser拉取用户数据 - 先做Activity读取操作再判断用户是否为Bot,无效操作多
- 没有判断用户是否已经持有目标身份组,重复调用Add/Remove接口容易触发Discord限流
- 没有利用
before参数过滤非活动状态变更的事件,所有用户信息变更(改昵称、改头像等)都会触发逻辑,浪费性能
修复后代码
private async Task UserUpdated(SocketGuildUser before, SocketGuildUser after) { // 先过滤机器人,提前返回减少无效操作 if (after.IsBot) return; // 先获取目标角色,建议把myguildid、myroleid做成全局只读常量 var targetGuild = after.Guild; var targetRole = targetGuild.GetRole(myroleid); if (targetRole == null) return; // 角色不存在直接返回避免后续报错 // 只有活动状态变化才处理,过滤其他用户信息变更事件 if (before?.Activity?.Name == after?.Activity?.Name) return; // 判断当前是否在玩指定游戏,一次性完成类型判断+空值检查 bool isPlayingTargetGame = after.Activity is Game game && game.Name.Equals("mygamename", StringComparison.OrdinalIgnoreCase); // 检查用户当前是否持有目标角色,避免重复调用接口 bool hasTargetRole = after.Roles.Any(r => r.Id == myroleid); if (isPlayingTargetGame && !hasTargetRole) { await after.AddRoleAsync(targetRole); } else if (!isPlayingTargetGame && hasTargetRole) { await after.RemoveRoleAsync(targetRole); } }
优化说明
- 用
is Game game语法一次性完成类型判断+空值判断+变量声明,从根源避免空引用异常 - 利用
before参数对比活动状态,只有活动变化时才执行后续逻辑,大幅减少无效执行次数 - 增加角色存在性、用户角色持有状态判断,避免无效API调用,降低触发Discord接口限流的概率
- 字符串比对用
StringComparison.OrdinalIgnoreCase忽略大小写,避免游戏名称大小写不一致导致匹配失败
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

