分配null会从对象中删除所有事件处理程序吗?

36

我在我的类中定义了一个新成员

protected COMObject.Call call_ = null;

这个类有一个我订阅的以下事件处理程序

call_.Destructed += new COMObject.DestructedEventHandler(CallDestructedEvent);

以下代码将会移除事件处理程序吗?

将成员设置为null如下所示:

call_ = null;

还是我必须使用 -= 取消订阅?


这取决于某些事件处理程序是否仍然持有对call_引用的引用。如果没有,垃圾回收器将清理它。 - TimTIM Wong
4个回答

36

是的,你应该使用重载的-=来取消订阅一个事件。

简单地将引用赋值为null并不能自动完成取消订阅。对象仍会继续监听该事件。


谢谢!你可以给我一些微软或其他网站的链接来验证吗? - Dor Cohen
1
@Dor 你不需要它- +3(可能在我完成之前还有更多)足以让你知道它是正确的。然而-这个关于VS2003天的事件讨论应该很清楚... http://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx - Andras Zoltan
8
比这个答案分数高得多的答案都是错的。但是它是正确的。主要问题是call_对象没有设置为null,只有call_被设置为null,它只是对该对象的一个引用,可能会有其他引用(在事件处理程序中)。归根结底,我们不是将对象设置为null,而是将引用设置为null。 - Jon Hanna
2
这在很大程度上取决于事件所涉及的对象是否会在某个时刻被收集;如果是,那么取消订阅并不值得。 - Marc Gravell

9
在设置为null或处理对象之前,您应该始终通过- =取消订阅事件处理程序(仅将变量设置为null将无法取消所有处理程序),如下面的MSDN摘录所示:
为了防止事件被引发时调用您的事件处理程序,只需取消订阅事件即可。为了防止资源泄漏,重要的是在释放订阅者对象之前取消订阅事件。在取消订阅事件之前,发布对象中支持该事件的多路委托具有对封装订阅者事件处理程序的委托的引用。只要发布对象保持该引用,您的订阅者对象就不会被垃圾回收。
在下面的链接中的“取消订阅”部分解释了这一点:如何:订阅和取消订阅事件(C#编程指南) 更多信息请参见:为什么您应该始终取消订阅事件处理程序

在OP的情况下,直接处理该对象是可以的,因为该对象本身就是事件发布者。但是回答这个问题,这样做直到它被垃圾回收才会取消订阅,这可能发生因为它是发布对象。 - TimTIM Wong

1
你必须使用减法赋值运算符 (-=) 来 取消订阅 事件。只有在所有订阅者都从事件中取消订阅之后,发布者类中的事件实例才会被设置为 null。

0

移除所有事件,假设事件是“Action”类型:

Delegate[] dary = TermCheckScore.GetInvocationList();

if ( dary != null )
{
    foreach ( Delegate del in dary )
    {
        TermCheckScore -= ( Action ) del;
    }
}

7
这是一个很糟糕的回答。如果您可以像字段事件一样访问TermCheckScore,那么您必须在声明类型中。这种情况下,只需将其设置为null即可。TermCheckScore = null; 可以做到与此相同的效果,但更加高效。 - Marc Gravell

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