为什么C#中的事件实现默认情况下不使用弱事件模式?

Kru*_*lur 19 .net c# events weak-references

这个问题可能会导致猜测性的答案,但我认为event在的实现背后有一个深思熟虑的设计决策.

只要事件的发布者处于活动状态,的事件模式就会使订阅者保持活动状态.因此,如果你没有取消订阅,你就会泄漏内存(好吧,并没有真正泄漏 - 但内存仍然不必要地占用).

如果我想阻止这种情况,我可以取消订阅事件或实现MSDN中提出的弱事件模式.

由于事件模式导致了很多问题(对于初学者?),问题是:为什么决定发布者保留对订阅者的强引用,而不是让它们独立或允许开发人员明确拥有strong或weak修饰符?

关于这个主题已经有了几个问题,答案听起来很合理,但没有一个真正回答为什么会这样.

usr*_*usr 21

一个原因当然是表现.GC句柄(为所有"异国情调"引用提供动力WeakReference)会带来性能成本.弱事件比"强"事件慢,因为它们需要GC句柄.存储委托的实例字段(默认情况下)实现强事件.这只是一个普通的托管引用,与任何其他引用一样便宜.

事件应该是一种非常通用的机制.它们不仅适用于您可能拥有几十个事件处理程序的UI场景.将很多复杂性和性能成本烘焙到这样一个基本语言功能中并不是一个明智的想法.

还存在由弱引用引起的语义差异和非确定性.如果您() => LaunchMissiles()与某些事件挂钩,您可能会发现有时会发射导弹.其他时候GC已经带走了处理程序.这可以通过引入另一个复杂程度的从属句柄来解决.

请注意,您可以透明地向订户实施弱事件.事件就像属性一样,它们仅仅是基于add和remove访问器方法的元数据和约定.所以这是(仅仅)关于.NET语言选择的默认值的问题.这不是CLR的设计问题.

我个人觉得很少有事件的强烈参考性质是一个问题.通常,事件连接在具有相同或非常相似的生命周期的对象之间.例如,您可以在ASP.NET中的HTTP请求的上下文中挂接所有您想要的事件,因为在请求结束时,所有内容都有资格进行收集.任何泄漏的大小都是有限的,而且寿命很短.

  • 我知道我可以自己实现弱版本;我只是想知道为什么它不是默认的。导弹的例子非常有道理,也是为什么强引用是一件好事并且是一个合理的决定的一个很好的例子。 (2认同)