假设我有一个类A,它可以触发一个名为X的事件。现在我有一个B类,在一个方法中我得到一个实例到A并将事件绑定到B中的一个处理程序:
public void BindEvent(A a)
{
a.X += AEventHandler;
}
我有三个问题。
当我现在将对B实例的引用设置为null时,它不会被垃圾收集,因为垃圾收集器认为它仍然在使用(因此保留了一个无用且可能干扰的B副本)在记忆中)。
当我有另一个对象c(C类)时,我有一个名为a的引用(“this.a = new A()”)。然后我调用“b.BindEvent(this.a)”,在c中我将a的引用设置为null(“this.a = null”)。这是否会将A的副本保留在内存中,因为它是通过b?
如果上述情况中的任何一个或两个都成立,我怎样才能最好地规避这些问题?如果我有一个事件处理程序的完整列表(比如“a.SomeEvent + = SomeMethod”这样的10行),我应该再次清理它们(“a.SomeEvent - = SomeMethod”)。我应该在代码中的哪个时间或地点做这些事情?
嗯,它有点模糊,但我不确定如何以更好的方式解释。如果我需要解释一些更详细的内容,请发表评论。
答案 0 :(得分:8)
所以:A
是发布商,B
是订阅者吗?
第一个项目符号:如果B
是AEventHandler
的实例 - 那么 仍然在使用中,所以不会,除非{{1实例无法访问。
a
和A
实例都无法访问,它们将被垃圾收集;事件没关系。如果B
可以访问,那么A
将保持活跃状态。但是,事件订阅从不使B
保持活跃状态;这是一种方式...... A
可以让A
保持活跃,但B
不会让B
保持活着。这涵盖了吗?
第三个问题:在大多数情况下,这两件事具有相似的生活费用,所以这不是问题。如果发布事件的事物比处理事件的事情长得多,那么它只会成为一个问题。在这种情况下,您只需要在自己之后进行宗教清理 - 例如:A
。特别是,由于这个原因,a.X -= AEventHandler
事件是邪恶。
答案 1 :(得分:4)
在销毁与之相关的类实例之前,您应该真正取消绑定事件处理程序。 (使用您的代码作为例子。)
public void UnbindEvent(A a)
{
a.X -= AEventHandler;
}
我也会问,为什么要将类变量设置为null?
答案 2 :(得分:2)
答案 3 :(得分:1)
是的,event是引用,如果你不注销,实现事件处理程序的对象将不会被垃圾回收。
你可以这样做:
删除所有已注册的活动,如果A知道他们何时不再使用。
class A
{
// clearing all registrations
private void ClearEvents()
{
X = null;
}
}
或者你在B中取消注册,如果B知道它何时不再使用它。您需要保留对a的引用才能取消注册。
您还可以实现IDisposable。
class B : IDisposable
{
private A registeredToA;
public void BindEvent(A a)
{
registeredToA = a;
registeredToA.X += AEventHandler;
}
public void Dispose()
{
registeredToA.x -= AEventHandler;
}
}
这是对代码的重大更改,因为B总是需要处理。