【问题标题】:Should I use event aggregator only to prevent memory leaks?我应该只使用事件聚合器来防止内存泄漏吗?
【发布时间】:2026-01-10 06:00:02
【问题描述】:

我们考虑使用Prism event aggregator 来减少由于事件引用导致的内存泄漏。

  1. 这本身是使用此模式的正当理由吗?其他好处现在对我们来说并不有趣。我们计划在模型组件而不是 UI 之间使用它。

  2. 我们的问题是一些开发人员忘记取消注册事件。我看到 Prism 有一种使用弱引用的风格,但它有 limitations。另一种风格强制显式取消订阅(),这又可以被遗忘。那么怎么样更好呢?

【问题讨论】:

    标签: c# events memory-leaks prism eventaggregator


    【解决方案1】:

    我们的问题是一些开发者忘记取消注册事件

    如果这是您的问题,切换到 Prism 事件聚合器(或使用任何其他实现)不会改善问题。

    将具有新的、非平凡的使用模式的新依赖项添加到混乱的情况中根本不会整理它。

    需要是清理你的代码。

    我建议不要使用新的代码库,而是使用静态分析工具,例如 fxCop(又名代码分析)、GendarmeNDepend。所有这些都能够检测到一些事件没有被取消挂钩或 IDisposable 没有正确实现的情况。

    使用静态分析,您可以冷静地识别需要清理的代码。使用内存分析器(如dotTrace Memory),您将能够找到最严重的违规者并及时清理它们。

    更新

    回答下面评论中的问题:

    对于确保事件脱钩的良好模式,您有什么建议?

    可能很难确保所有事件都已取消订阅 - 但考虑到事件的实现方式(有关详细信息,请参阅 CLR via C#),您可以通过确保丢弃所有事件订阅来作弊。

    代替

    public event EventHandler<Fu> FuBar;
    

    自己处理事件订阅,像这样:

    public event EventHandler<Fu> FuBar {
        add { mFuBar += value; }
        remove { mFuBar -= value; }
    }
    
    private EventHandler<Fu> mFuBar;
    

    然后,在您的类上实现IDisposable,并在您的Dispose() 方法中将mFuBar 设置为null,丢弃订阅。然后,FxCop(和其他工具)可以告诉您您是否未能 Dispose 类。

    【讨论】:

    • +1,完全同意。 EventAggregator 意味着作为跨应用程序的消息代理,并将其硬塞到您通常使用常规 .NET 事件的地方有时并不重要(UI 之间的串扰,必须为每次使用创建不同的事件类以减轻这种情况等) ...不理想)。这不是 EventAggregator 想要解决的问题。
    • 您有什么建议作为确保事件脱钩的好模式?至少对于在创建对象时挂钩并且在对象的有用生命周期内保持不变的事件来说,最好有一种方法让相同的代码块处理订阅和取消订阅(从而确保相同的事件将像订阅一样退订)。不幸的是,我知道在 vb 或 C# 中没有什至远程干净的方式来做这样的事情。你有好的模式吗?
    • 在事件源中实现 IDisposable 并没有真正增加任何价值。当订阅者的生命周期比事件源短时,就会发生内存泄漏。因此,处置事件源确实可以防止在订阅者仅因为事件源引用它们而生活在内存中时已经发生的泄漏。在这种情况下使用弱事件模式是解决方案。
    • 以这种方式使用IDisposable有助于减轻内存泄漏的影响;如果您在处理对 web 应用程序的请求的上下文中工作 - 无论如何都将被丢弃,那么它不会增加任何内容。但是,如果您在 WinForms/WFP/UWP 应用程序中工作,而这些应用程序的寿命往往会更长,这样的缓解措施可以防止错误导致应用程序崩溃。
    • 关于静态分析器的好点,但@PramodBR 就在这里。 IDisposaility 在这里没有添加任何内容。