将事件设置为Null

18

我有这样的一段代码:

public class SomeClass
{
    int _processProgress;
    public int ProcessProgress 
    { 
        get { return _processProgress; } 
        set 
        { 
            _processProgress = value; 
            if (ProcessProgressChanged != null) 
                ProcessProgressChanged(value);
        } 
    }

    public delegate void ProcessProgressChangedEventHandler(int progressPercentage);
    public event ProcessProgressChangedEventHandler ProcessProgressChanged;

    public void ClearProcessProgressChangedEvent()
    {
        this.ProcessProgressChanged = null;
    }
}

当我调用ClearProcessProgressChangedEvent()方法时,它会取消订阅ProcessProgressChanged事件中的所有方法吗?

我的代码使用C#编写,框架为4,在VS2010 Pro中构建,项目是Winforms。

请帮忙解答,提前感谢。


2
这个问题不是重复的。那个问题是关于将注册了事件的对象设置为null。而这个问题是关于将事件本身设置为null。 - Wes
ClearProcessProgressChangedEvent 不能从析构函数/终结器中调用。 - samus
2个回答

23

实际上,它会有效地清除订阅者列表 (通过将基础委托字段设置为null),这样下一次设置ProcessProgress时,不会调用任何处理程序。它并没有真正将事件设置为null - 它只是将底层字段设置为null。只是 C# 编译器使用单个声明创建了一个事件 (一个订阅/取消订阅的方法对) 和一个字段 (用于存储处理程序)。

您可能会发现我关于事件和委托的文章有用。

请注意,您当前的事件触发代码并不是线程安全的。我不知道是否需要,但您可能要考虑使用:

set 
{ 
    _processProgress = value; 
    var handlers = ProcessProgressChanged;
    if (handlers != null) 
    {
        handlers(value);
    }
}

如果在空性检查之后但在调用之前,最后一个处理程序被取消订阅,那么这样就不会出现NullReferenceException


设置 this.ProcessProgressChanged = null; 会导致内存泄漏吗(也就是说,这不是 -= 的替代品)? - samus
1
@samis:不会导致内存泄漏。 - Jon Skeet
1
语言的新版本允许您编写handlers?.Invoke(value);进行空值检查,而无需将其包装在if语句中。 - Delta
1
@Delta:是的,但每次有新的语言版本时我不会回顾所有旧的答案... - Jon Skeet
1
没问题,我主要是想告知未来看到这篇帖子的人们,就像我一样,并且认为这可能对那些人有所帮助 :) - Delta
目前Jon已经回答了35,668个问题,真是不容易啊 :) - undefined

6

是的,这将会取消所有人的活动订阅。在此链接中有一个(我认为有点间接)的参考:

当所有订阅者都从事件中取消订阅时,发布者类中的事件实例将设置为null


2
当所有订阅者从事件中取消订阅后,发布者类中的事件实例将被设置为null。反之亦然吗?将事件实例设置为null是否会取消所有订阅者的订阅(在这种特定情况下可能不适用,因为正在将对事件的引用“this.ProcessProgressChanged”设置为null)? - samus
2
@samis 如果将引用设置为 null,则表示没有任何内容引用组合委托,因此它将被垃圾回收,并且不会阻止订阅者的垃圾回收。 因此,这个简单的操作,设置为 null,即取消订阅所有订阅者。 - Maxim T

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