如何识别触发OnUpdate事件的Client会话?代码调试异常求助
解决多Client会话事件触发的识别问题
问题原因
你遇到的是C#闭包陷阱:for循环中的变量i是被闭包捕获的引用,而非当前迭代的具体值。循环结束后i的最终值为2(因为循环条件i < Clients.Count在i=2时不满足,退出循环),所以所有事件触发时都会使用这个最终值,导致日志始终显示i=2。
解决方案
方法一:在循环内创建局部变量捕获当前索引
在每次循环迭代中创建一个局部变量,保存当前的i值,让闭包捕获这个局部变量的引用:
static async Task Main(string[] _) { Helpers.Log = (l, s) => Debug.WriteLine(s); Clients.Add(new Client(what => Config(what, "session1"))); Clients.Add(new Client(what => Config(what, "session2"))); for (int i = 0; i < Clients.Count; i++) { // 创建局部变量保存当前迭代的索引值 int sessionIndex = i; Clients[i].OnUpdate += updates => Client_OnUpdate(updates, sessionIndex); MyUsers.Add(new User()); MyUsers[i] = await Clients[i].LoginUserIfNeeded(); var dialogs = await Clients[i].Messages_GetAllDialogs(); dialogs.CollectUsersChats(Users, Chats); } Console.ReadKey(); } private static async Task Client_OnUpdate(IObject arg, int sessionIndex) { Debug.WriteLine($"会话索引 = {sessionIndex}"); }
方法二:直接捕获Client实例(更推荐)
跳过索引,直接将触发事件的Client实例传递给处理方法,逻辑更直观且避免依赖列表索引:
static async Task Main(string[] _) { Helpers.Log = (l, s) => Debug.WriteLine(s); Clients.Add(new Client(what => Config(what, "session1"))); Clients.Add(new Client(what => Config(what, "session2"))); foreach (var client in Clients) { // 捕获当前迭代的Client实例 Client currentClient = client; currentClient.OnUpdate += updates => Client_OnUpdate(updates, currentClient); var user = await currentClient.LoginUserIfNeeded(); MyUsers.Add(user); var dialogs = await currentClient.Messages_GetAllDialogs(); dialogs.CollectUsersChats(Users, Chats); } Console.ReadKey(); } private static async Task Client_OnUpdate(IObject arg, Client client) { // 根据Client实例的属性识别会话,例如会话名称 Debug.WriteLine($"触发事件的会话:{client.SessionName}"); // 假设Client类包含SessionName属性 }
说明
- 方法一中的局部变量
sessionIndex在每次循环迭代时都会生成新的实例,闭包捕获的是该变量的引用,因此每个事件处理程序都会保留对应迭代的索引值。 - 方法二更健壮:无需依赖列表索引,后续对
Clients列表的修改(如增删元素)不会影响会话识别,直接通过Client实例即可定位到触发事件的会话。
内容的提问来源于stack exchange,提问作者Vipz
相关产品推荐
相关产品推荐

