弱引用和事件处理

34

如果一个事件是唯一持有引用的东西,并且我们需要该对象被垃圾回收,那么通过弱引用实现事件处理是否是一个好的实践方式?

作为论据:

有人说如果你订阅了某个事件,那么取消订阅是你的责任,你应该这样做。


问题在于:对象被垃圾收集时,该事件被触发的几率有多大?为什么首先要使用WeakReference? - Jon Limjap
@Jon Limjap,如果没有使用WeakReference,那么机会不是零吗?因为该事件跟踪对象,因此它将不会被收集。 - fostandy
2
@fostandy:不,事件的发布者不会因为订阅者而保持活动状态,只有反过来才行。为了让订阅者在不必先取消订阅的情况下被垃圾回收,应该使用WeakReference。请参见:https://dev59.com/CHVC5IYBdhLWcg3wbghT#298276 - angularsen
4个回答

15

养成在合适时机取消事件订阅的好习惯是很不错的,但有时候并没有明显的“清理”方法可以使用。我们最近发表了一篇博客文章,介绍了使用WeakReference轻松订阅事件的方法。


12

弱委托模式是CLR中应该存在的东西。普通事件展示“当你还活着时通知我”的语义,然而我们经常需要“在我还活着时通知我”。仅仅在WeakReference上拥有委托是错误的,因为委托本身也是一个对象,即使接收者仍然活着并且有传入引用,委托本身仅被所述WeakReference引用,并将立即被回收。参见此旧帖子以获取实现示例。


7

弱引用本身并不能解决委托持有引用的问题。在 Prism(www.microsoft.com/compositewpf)中提供的组合应用程序库中,有一个 WeakDelegate 类可以从源代码中获取。WeakDelegate 基本上使用反射,在短暂的时间内创建一个委托,然后释放它,从而不保留任何指针。在 CAL 中,它被 EventAggregator 类使用,但您可以自由地将其拆分出来以供自己使用,因为它是根据 MS-PL 许可证发布的。


-2

虽然您提出的解决方案可以解决一组问题(事件引用管理和内存泄漏预防),但很可能会引发一组新问题。

我能看到的一个问题是,在事件处理过程中,如果源对象被垃圾回收(因为它只使用了弱引用),任何访问源对象的代码都将导致空引用异常。您可以认为事件处理程序不应访问源对象或者必须具有强引用,但可以认为这可能比您试图解决的问题更糟糕。


1
当CLR已经执行事件处理程序时,堆栈将保留对“this”的引用,对象将不会被收集。 - Ilya Ryzhenkov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接