C# 自动取消订阅事件

C# 自动取消订阅事件,c#,events,memory-leaks,event-handling,C#,Events,Memory Leaks,Event Handling,我有一个静态类,它发布一些事件。所以我有很多不同的小类,它们有不同的生命周期来订阅这个事件 我现在发现,这会导致内存“泄漏”,因为订阅类在订阅一个更长寿的事件时仍然有效。我知道这是通过使用内存驱动器发生的,我读到了关于这个问题的文章 我无法手动取消订阅,因为列表中可能有数百个“客户”。这个列表将被清除。所以我不能(也不想)手工退订 我读到“弱事件模式”可能在这里有所帮助。有人能告诉我一个“简单”的方法来实现这一点吗?到目前为止,我所发现的要么太简单,无法在实践中使用,要么太复杂,无法在一开始就理

我有一个静态类,它发布一些事件。所以我有很多不同的小类,它们有不同的生命周期来订阅这个事件

我现在发现,这会导致内存“泄漏”,因为订阅类在订阅一个更长寿的事件时仍然有效。我知道这是通过使用内存驱动器发生的,我读到了关于这个问题的文章

我无法手动取消订阅,因为列表中可能有数百个“客户”。这个列表将被清除。所以我不能(也不想)手工退订

我读到“弱事件模式”可能在这里有所帮助。有人能告诉我一个“简单”的方法来实现这一点吗?到目前为止,我所发现的要么太简单,无法在实践中使用,要么太复杂,无法在一开始就理解它

或者对于这个案例有什么“最佳实践”吗

提前谢谢

更新:
根据jbl的回答,我发现了这一点(http://blogs.msdn.com/b/greg_schechter/archive/2004/05/27/143605.aspx)作为可能的解决办法。有什么评论吗?它相当古老(2004年),因此可能有更好的解决方案?

最佳实践:当类订阅由非该类构造的对象生成的事件时,始终实现
Dispose
模式

然后在Dispose方法中删除处理程序

public NotificationServiceAccessor(ObjectWithEvent objectWithEvent)
{
    _notificationService = new NotificationService();
    _notificationService.StatusChanged += NotificationService_StatusChanged; // Local object, no Dipose

    _objectWithEvent = objectWithEvent;
    _objectWithEvent.AnEvent += AnEventHandler(); // Event that has to be disposed.
}

    #region IDisposable Members

    protected bool Disposed { get; private set; }

    private void Dispose(bool disposing)
    {
        if (!this.Disposed)
        {
            this.InternalDispose(disposing);
        }

        this.Disposed = true;
    }

    protected virtual void InternalDispose(bool disposing)
    {
        if (disposing)
        {
                        // Dispose here the event handlers
                        _objectWithEvent.AnEvent -= AnEventHandler()
        }

        // Dispose here only unmanaged objects 
        // Don’t use managed objects here because maybe 
        // they have been finalized already
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~NotificationServiceAccessor()
    {
        this.Dispose(false);
    }

    #endregion

从未实现过类似的东西,但我会尝试(使用静态类或单例,由您选择):

  • 让静态类维护对客户端事件处理程序的WeakReference的静态集合
  • 客户端不直接订阅事件。静态类公开subscribe和unsubscribe方法,这些方法在弱引用集合中添加/删除处理程序
  • 静态类是唯一一个直接订阅事件的类
  • 在事件触发时,静态类枚举弱引用集合,并为仍处于活动状态的引用运行处理程序(删除空引用)

希望这将有助于

这方面的任何示例实现?@SoMoS:完全不同意,这是一种最佳实践。这只是一种方法,在某些情况下是适用的。我感谢你的这种方法。但我认为这在“任何”情况下都不会帮助我。因为有可能订阅者的最后一个引用是“空的”,但我不能100%确定调用Dispose方法。@丹尼斯:好的,我总是使用它,但如果你知道什么时候最好不要遵循这个规则,请告诉我们。@SoMoS:这种方法只允许显式调用
IDisposable.Dispose
,取消订阅事件。这反过来又假设您在某处保留了对一次性对象的引用。有许多用例,当不可能或不适合保留对一次性对象的引用时。例如,看看这个问题——这里我们有一个静态事件,这意味着,任何一段代码都可以在进程生命周期中订阅这些事件。你真的想追踪所有这些一次性物品吗?看看这个帖子,Fredric对你的问题的解释真的很有帮助,你看过WPF()中的
WeakEventManager
?@Dennis:我现在正在使用WinForms。所以我不是100%能够使用WPF的东西。但我会读一读这个话题。谢谢@chiffre:嗯,使用
WeakEventManager
并不意味着“使用WPF”,不需要呈现WPF控件。@dennis:但我必须引用WPF程序集。我不会吗?所以你需要为每一种活动上一节课?如何确保“unsubscribe”被调用/完成?不,WeakReference是处理程序的包装器(“不知何故”类似于将其包装到对象中)。由于WeakReference不会阻止垃圾收集,因此不需要确保已调用unsubscribe。当相应的对象已被垃圾回收时,弱引用的内容将为null