根据我的理解,当不再需要对象时,最佳做法是取消订阅事件的任何对象中的所有事件处理程序。
这样做是为了避免在给定对象可能处于无效状态时处理对象中的事件(毫无疑问,我可能不知道的其他原因)。
鉴于上述情况,我发现自己在注册任何形式的事件处理程序的所有对象上实现了IDisposible
。但是,这会产生必须在给定对象上显式调用Dispose()
的明显复杂性。
最后,我发现自己不确定是否需要这种额外的复杂性,或者我是否应该简单地在对象析构函数中执行事件取消订阅。然而,鉴于对象销毁是不确定的,这显然留下了意外行为的可能性。
那么是否应该IDisposable
所有注册事件的对象?或者有没有更适合的替代方法?
我建议,如果一个对象订阅了来自外部对象的通知,无论这些对象使用事件、IObservable
还是其他订阅方式,释放该对象都应该确保这些订阅被取消; 最自然的方法是使用它外部对象支持的正常取消方式。
我进一步建议,如果一个对象接受来自外部对象的订阅请求,如果/当很明显不会再向这些订阅者发送通知时,它应该销毁对这些对象的引用。 通常,一旦对象发送了Dispose
本身所需的任何通知,它就不必发送任何进一步的通知,因此应该销毁其订阅列表,除非其语义要求保留它们超出该范围。
虽然 .NET 事件模式不能方便地确保取消订阅,但无法从共享对象取消订阅通常会导致代码"通常"有效,但会有一些难以验证的要求。 在创建并保留了一些对象的情况下,或者创建了无限数量的对象并放弃了所有对象,则对象之间的相互引用不会导致内存泄漏,因为在前一种情况下,即使相互引用不存在,也需要保留对象,而在后一种情况下,尽管相互引用,它们将不复存在。 但是,创建无限数量的对象并且除了少数对象之外的所有对象都被放弃的情况可能是灾难性的。 即使许多对象的消费者自然会遵守其中一种使用模式,要求所有人都必须遵守其中一种或全部遵守另一种,而不指定哪种模式是可以接受的,这是相当尴尬的。
您是正确的,应该取消订阅事件,因为如果您不这样做,它也可能导致内存泄漏。
我不确定是否有建议或标准的方法可以做到这一点,但是如果一个类需要清除内容,那么它通常会实现 IDisposable。
另一种方法是"记住"在正确的位置取消订阅 - 至少 IDisposable 使这一点更加明显,对于以后访问您的代码的人来说尤其重要。