C#两种事件订阅方式差异及Binance.Net中Lambda订阅是否需手动取消
事件订阅写法差异及Lambda订阅取消规则
两种订阅方式的核心区别
- 命名方法订阅(示例1):你声明了独立的
PortfolioService_Exception方法作为事件处理逻辑,每次+=/-=操作的都是同一个方法对应的委托实例,操作完全可控,可以正常配对完成订阅和取消。 - 匿名Lambda订阅(示例2):你直接写在
+=后的Lambda表达式是运行时生成的临时委托实例,没有显式变量持有它的引用,哪怕你再写一行完全相同的Lambda代码,生成的也是不同的委托实例,因此无法直接通过-=匹配到之前注册的处理器。
Lambda订阅是否需要手动取消?
需要。只要完成了事件订阅,事件源(也就是你代码里的subscription.Data对象)就会持有处理器的引用:你的Lambda因为捕获了当前类的_logger成员,还会反向持有当前类的实例引用。如果不取消订阅,且subscription对象的生命周期长于你的服务类,会导致你的服务类无法被GC回收,出现内存泄漏。
但匿名Lambda无法直接用-=取消,有两种解决方式:
- 提前把Lambda存到委托变量中,订阅和取消都使用同一个变量:
// 声明委托变量持有Lambda引用 Action<Exception> exceptionHandler = ex => { _logger.LogInformation($"Error: {ex.StackTrace}"); }; // 订阅 subscription.Data.Exception += exceptionHandler; // 取消订阅 subscription.Data.Exception -= exceptionHandler;
- 不需要单独取消事件的场景下,可以直接调用
UpdateSubscription提供的CloseAsync()方法,该方法会关闭整个数据流订阅,底层会自动清理所有绑定的事件处理器,无需单独操作-=。
结合业务代码的补充提示
你当前代码中注册的匿名Exception处理器,只要在订阅生命周期结束时调用CloseAsync()关闭用户数据流,就不会出现内存泄漏问题。如果你会多次执行InitAsync()创建新的订阅,需要注意及时清理旧的订阅实例,避免资源泄漏。
内容的提问来源于stack exchange,提问作者nop
相关产品推荐
相关产品推荐

