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

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

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

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

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

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

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

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

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

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

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