You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中为DisplaySettingsChanged事件添加Lambda表达式会导致内存泄漏吗?

结论

直接使用匿名Lambda表达式绑定SystemEvents.DisplaySettingsChanged事件且不手动卸载的写法不可行,一定会造成内存泄漏,不能用来替代原有带+=/-=的命名方法注册方案。

原因说明
  • SystemEvents类的所有事件都是静态事件,其生命周期和整个应用程序域保持一致,只要注册了事件处理器,静态事件实例就会一直持有该处理器的引用,直到程序退出或者手动卸载处理器。
  • 匿名Lambda表达式没有可复用的引用标识,你无法在后续通过-=操作符匹配到之前注册的Lambda实例,哪怕你写一个逻辑完全一致的Lambda去执行卸载,也只会生成一个新的委托实例,无法卸载之前注册的处理器。
  • 对于你提供的CompositionMetrics场景,Lambda内部必然会捕获当前类的实例成员(比如hwndSource、属性字段等),这会导致静态事件直接持有整个CompositionMetrics实例的引用,就算你调用了Dispose方法,GC也无法回收该实例,直接产生内存泄漏。同时已经被标记释放的实例被事件回调时,还可能触发不可预期的运行时异常。
可选的Lambda兼容写法(不推荐)

如果你非要用Lambda写法,必须将Lambda委托存为类的字段,才能实现后续的卸载,写法如下:

public sealed class CompositionMetrics : IDisposable
{
    private readonly HwndSource hwndSource;
    private readonly EventHandler _displaySettingsChangedHandler;

    public CompositionMetrics(HwndSource source)
    {
        hwndSource = source;
        _displaySettingsChangedHandler = (_, _) =>
        {
            // 你的逻辑代码
        };
        SystemEvents.DisplaySettingsChanged += _displaySettingsChangedHandler;
    }

    public void Dispose()
    {
        SystemEvents.DisplaySettingsChanged -= _displaySettingsChangedHandler;
    }
    // 其余属性、方法代码省略
}

这种写法和原有命名方法的方案没有本质区别,没有额外收益,因此更推荐你保留原有的命名方法注册事件的写法,可读性和可维护性更好。

内容的提问来源于stack exchange,提问作者Selastin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 15:54:04