如何在VB.NET中引发事件之前检查订阅者

时间:2013-05-23 10:15:08

标签: .net vb.net event-handling raiseevent

在C#中,你可以这样做:

if (Changed != null)
    Changed(this, EventArgs.Empty);

但是你在VB.NET中做了什么?

RaiseEvent,但

RaiseEvent Changed(Me, EventArgs.Empty)

实际检查某事已订阅该事件?

2 个答案:

答案 0 :(得分:14)

与其C#等价物不同,如果没有侦听器,VB.NET中的RaiseEvent引发异常,因此首先执行空检查并非绝对必要。

但是如果你想这样做,那就有它的语法。您只需要将Event作为后缀添加到事件名称的末尾。 (如果不这样做,则会出现编译错误。)例如:

If ChangedEvent IsNot Nothing Then
    RaiseEvent Changed(Me, EventArgs.Empty)
End If

就像我上面所说的那样,我不确定这样做是否有任何实际好处。它使您的代码非惯用且更难以阅读。我在这里介绍的技巧并没有特别详细记录,大概是因为RaiseEvent关键字的全部要点是在后台处理所有这些问题。这种方式更加方便直观,是VB.NET语言的两个设计目标。

你应该自动处理这个问题的另一个原因是因为用C#方式做这件事有点困难。您显示的示例代码段实际上包含竞争条件,等待发生的错误。更具体地说,它不是线程安全的。您应该创建一个临时变量来捕获当前的事件处理程序集,然后进行空检查。像这样:

EventHandler tmp = Changed;
if (tmp != null)
{
    tmp(this, EventArgs.Empty);
}

Eric Lippert撰写了一篇关于此here的精彩博客文章,其灵感来自this Stack Overflow question

有趣的是,如果您检查使用RaiseEvent关键字的反汇编VB.NET代码,您会发现它正在执行以上正确的 C#代码所做的事情:声明临时变量,执行空检查,然后调用委托。为什么每次都要混淆你的代码呢?

答案 1 :(得分:2)

直接转换是:

If Changed IsNot Nothing Then
    Changed(Me, EventArgs.Empty)
End If

RaiseEvent必须用于在VB.NET中引发事件,您不能简单地调用该事件。如果没有侦听器,则不会使用RaiseEvent抛出异常。

请参阅:http://msdn.microsoft.com/en-GB/library/fwd3bwed(v=vs.71).aspx

因此应使用以下内容:

RaiseEvent Changed(Me, EventArgs.Empty)