【问题标题】:How do you find out what is subscribed to an event in C#?在 C# 中如何找出订阅了事件的内容?
【发布时间】:2023-03-11 03:45:01
【问题描述】:

我正在处理的应用程序存在内存泄漏问题。经验告诉我,垃圾收集语言最先遇到内存泄漏的地方之一是处理订阅事件并且以后无法取消订阅。第二个与存储静态有关。我是 C# 新手,对不透明的事件类型感到很沮丧。

我们通过抽签发现了一些双重订阅错误,但该应用程序确实将事件用于许多事情。虽然我们很清楚取消订阅您订阅的所有内容的原则,但仍然存在内存泄漏。我想系统地确定订阅了什么。

编辑:

感谢您提供指向 GetInvocationList() 方法的指针。我正在尝试创建一个可以动态转储结果的调试工具。问题是我发现的解决方案在 .Net 2 中有效,但在 .Net 3.5 中不再有效。本质上,它告诉您为 EventInfo 获取相应的 FieldInfo(分别为反射、GetField 和 GetEvents)。但是.Net 3.5中没有对应的FieldInfo,EventInfo也不会让我得到调用列表。

我只想转储事件列表及其 InvocationList 以进行调试。

【问题讨论】:

  • 查看我上个月对类似问题的回答,C# Event Based Memory Leaks。
  • 我很难选择这两者中的哪一个应该得到“官方”答案,因为它们都解决了我需要的不同部分。最后我选择了回答标题中问题的那个,虽然 n8wrl 的回答在不同方面都一样好。

标签: c# debugging events


【解决方案1】:

尝试在event 上使用名为GetInvocationList 的方法。

这将返回一个订阅事件的委托数组。

数组将按照添加的顺序包含委托。这也可以用来从列表中挑选和调用特定的委托,而调用event.Invoke 方法将调用它们(但只给你最后调用的委托的返回值)

【讨论】:

    【解决方案2】:

    您肯定正确地怀疑事件订阅是导致内存“泄漏”的原因。多年前,我们发现了一个应用程序范围内的静态对象订阅 ASP.NET 页面事件的问题——您可以猜到那里发生了什么。

    解决此问题的另一种方法是从发布商的角度。让所有订阅者都取消订阅可能不方便,但如果发布者需要被销毁/超出范围,也许可以触发它以将其所有事件设置为 null - 有效地取消订阅每个人并打破循环。

    如果发布者的生命周期更长,并且是保持其他对象活动的东西,那么您可能必须执行前面建议的 GetInvocationList 操作。但我认为这只是为了调试问题 - 找出谁在不应该关注事件的情况下关注事件。

    最后,您可以考虑一些基于 WeakReferenced 的自定义事件订阅机制。

    【讨论】:

    • 这也很有帮助。我将了解如何在具有它们的对象上连接 Dispose() 方法以清除侦听器。我仍然需要有效地检查结果。
    猜你喜欢
    • 2021-07-31
    • 2010-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-25
    • 1970-01-01
    相关资源
    最近更新 更多