【发布时间】:2016-04-21 10:26:24
【问题描述】:
当我无法确定地取消订阅时,我正在使用弱事件(否则我更喜欢 += 和 -= 而不是弱事件):
class SomeType
{
public SomeType(...)
{
// object doesn't know when it will be removed
WeakEventManager(SomeSource, EventArgs).AddHandler(someSourceInstance,
nameof(SomeSource.SomeEvent), (s, e) => { ... });
}
}
这样,如果对象被垃圾回收,则不会调用事件处理程序。完美。
但是。如果对象还没有被垃圾回收(但是没有更多的强引用),那么事件处理程序仍然会被调用。
我的问题比较笼统:使用弱事件时应该怎么做?使用弱事件时,我是否应该期望在事件处理程序中调用无效?还是我应该force GC 来避免这种情况(某种确定性的“清理”)?还有什么?
【问题讨论】:
-
你搞错了——如果订阅者只能通过事件处理程序保持活动状态,那么弱事件就会允许订阅者被垃圾回收。他们不会仅仅因为订阅者有资格获得 GC 就摆脱事件处理程序,这是一个副作用。您可以将其称为“无效呼叫”,但事实并非如此。所以简短的回答是“是的,你应该期待这样的电话”;更长的时间是“您甚至在做什么,这是一个问题,您是否缺少可以使您的意图明确的代码”?
-
@JeroenMostert,由于缺少
-=,我发生了内存泄漏。提供退订并不简单(我没有说不可能),因此我尝试使用弱事件。他们完美地解决了内存泄漏问题,但出现了另一个问题......因此我的问题。我应该如何明确“这个对象需要调用这个方法”的意图?IDisposable? -
IDisposable是一种方式,是的。这是 C# 用于确定性清理的主要机制。虽然在技术上仅用于释放非托管资源,但它在框架中广泛用于确定性清理,即使不涉及非托管资源也是如此。它具有语言支持 (using) 的优势,并清楚地向开发人员发出该对象应明确发布的信号。然而,比IDisposable更好的是找出对象的所有权规则,并让所有者负责“关闭”对象,如果可能的话。 -
是的,这就是“所有权”的运作方式——如果直接上一级无法制定法律,则必须向上踢,以此类推。您不能让垃圾收集为您完成繁重的工作 - 它旨在节省内存(必要时!),而不是实现您可以搭载的生命周期系统。特别是,如果编写得当,即使没有垃圾收集,您的应用程序也应该正确运行,因为我们拥有(比如说)TB 级的内存并且永远不需要释放任何东西。如果不是,则说明您遇到了设计错误。
-
为什么事件处理程序运行很重要?如果你能让它“无所谓”,你的问题就解决了。如果这不可能,那么您在某处没有在代码中表达的隐含功能需求。
标签: c# garbage-collection weak-events