【问题标题】:How to check for subscribers before raising an event in VB.NET如何在 VB.NET 中引发事件之前检查订阅者
【发布时间】:2013-05-18 15:43:23
【问题描述】:

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

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

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

RaiseEvent,但是是

RaiseEvent Changed(Me, EventArgs.Empty)

实际上是在检查是否有东西订阅了该事件?

【问题讨论】:

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


【解决方案1】:

直接转换是:

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)

【讨论】:

  • 我看过这篇文章,但没有说明如果没有听众会发生什么。
【解决方案2】:

与它的 C# 等效项不同,VB.NET 中的RaiseEvent不会在没有侦听器的情况下引发异常,因此没有必要首先执行 null 检查。

但如果你想这样做,它有一个语法。您只需将Event 作为后缀添加到事件名称的末尾即可。 (如果你不这样做,你会得到一个编译器错误。)例如:

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

不过,就像我在上面所说的那样,我不确定这样做是否有任何真正的好处。它使您的代码不习惯并且更难阅读。我在这里介绍的技巧并不是特别有据可查,大概是因为RaiseEvent 关键字的全部意义在于在后台为您处理所有这些。这样更方便直观,VB.NET 语言的两个设计目标。

您可能应该让它自动处理的另一个原因是因为在使用 C# 方式时很难正确处理它。您展示的示例 sn-p 实际上包含一个竞争条件,一个等待发生的错误。更具体地说,它不是线程安全的。您应该创建一个捕获当前事件处理程序集的临时变量,然后进行空检查。像这样的:

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

Eric Lippert 有一篇关于 here 的精彩博客文章,灵感来自 this Stack Overflow question

有趣的是,如果您检查使用 RaiseEvent 关键字的反汇编 VB.NET 代码,您会发现它与上述 正确 C# 代码所做的完全一样:声明一个临时变量,执行空检查,然后调用委托。为什么每次都把你的代码弄得乱七八糟?

【讨论】:

  • 是的,知道线程安全。但是对于我编写的代码,除非我知道我的代码将与线程一起使用,否则我会选择框架方法:只有我的静态方法才能保证是线程安全的。
  • @user 这是有风险的。您应该始终尽可能地努力编写线程安全的代码,这样当您决定稍后返回并添加额外的线程时,您就不必重新编写所有内容。如果我写的东西不是线程安全的并且我不打算这样做,我会用这样的解释很好地评论它。以后省了不少苦。
  • 如果您想要求至少有人在听并提出错误以了解某些管道未正确连接,这将很有帮助。
猜你喜欢
  • 2016-10-30
  • 1970-01-01
  • 2020-01-01
  • 1970-01-01
  • 2020-09-20
  • 2018-01-24
  • 1970-01-01
  • 1970-01-01
  • 2011-09-10
相关资源
最近更新 更多