事件处理程序不是线程安全吗?

所以我已经阅读过,而不是直接调用事件

if (SomeEvent != null) SomeEvent(this, null); 

我应该这样做

 SomeEventHandler temp = SomeEvent; if (temp != null) temp(this, null); 

为什么会这样? 第二个版本如何变得线程安全? 什么是最佳做法?

事件在代表列表中真的是语法糖。 当您调用该事件时,这实际上是在该列表上进行迭代并使用您传递的参数调用每个委托。

线程的问题在于它们可以通过订阅/取消订阅来添加或删除此集合中的项目。 如果他们在迭代集合时执行此操作,则会导致问题(我认为会抛出exception)

目的是在迭代之前复制列表,这样就可以防止对列表进行更改。

注意:现在,即使您取消订阅也可以调用您的侦听器,因此您应该确保在侦听器代码中处理此问题。

IMO,其他答案错过了一个关键细节 – 委托(因此事件)是不可变的 。 这样做的意义在于,订阅或取消订阅事件处理程序不会简单地将/追加/删除到列表中 – 而是列表替换为具有额外(或少一个)项目的新列表。

由于引用是primefaces的,这意味着在您执行此操作时:

 var handler = SomeEvent; 

你现在有一个无法改变的严格实例,即使在下一个皮秒中另一个线程取消订阅(导致实际事件字段变为null )。

所以你测试null并调用它,一切都很好。 当然注意,在一个认为它在皮秒前取消订阅的对象上仍然存在令人困惑的事件!

最佳实践是第二种forms。 原因是另一个线程可能在’ if ‘测试和调用之间为null或更改SomeEvent

这是一篇关于.NET事件和线程竞争条件的好文章。 它涵盖了一些常见的场景,并在其中有一些很好的参考。

希望这可以帮助。